预编译语句

多次执行的 CQL 语句可以被预编译并存储在 PreparedStatement 对象中,以提升查询性能。 驱动程序和 Cassandra 都会维护一个 PreparedStatement 查询与其元数据之间的映射关系。 你可以通过以下抽象来使用预编译语句:spring-doc.cadn.net.cn

使用CqlTemplate

CqlTemplate 类(及其异步和响应式变体)提供了多种方法,可接受静态 CQL、Statement 对象以及 PreparedStatementCreator。 接受静态 CQL 且不带额外参数的方法通常会直接运行该 CQL 语句,不做进一步处理。 接受静态 CQL 并配合参数数组的方法(例如 execute(String cql, Object…​ args)queryForRows(String cql, Object…​ args))则使用预编译语句(prepared statements)。 在内部,这些方法会创建 PreparedStatementCreatorPreparedStatementBinder 对象,用于准备语句并在稍后将值绑定到该语句以执行。 Spring Data Cassandra 通常对预编译语句使用基于索引的参数绑定。spring-doc.cadn.net.cn

自 Cassandra Driver 4 版本起,预编译语句(prepared statements)已在驱动程序层面进行缓存,从而无需在应用程序中手动跟踪预编译语句。spring-doc.cadn.net.cn

以下示例展示了如何使用带参数的预编译语句执行查询:spring-doc.cadn.net.cn

String lastName = cqlTemplate.queryForObject(
		"SELECT last_name FROM t_actor WHERE id = ?",
		String.class, 1212L);
Mono<String> lastName = reactiveCqlTemplate.queryForObject(
	"SELECT last_name FROM t_actor WHERE id = ?",
	String.class, 1212L);

在需要对语句准备和参数绑定进行更多控制的情况下(例如,使用命名绑定参数),你可以通过调用带有 PreparedStatementCreatorPreparedStatementBinder 参数的查询方法,完全控制预编译语句的创建和参数绑定:spring-doc.cadn.net.cn

List<String> lastNames = cqlTemplate.query(
		session -> session.prepare("SELECT last_name FROM t_actor WHERE id = ?"),
		ps -> ps.bind(1212L),
		(row, rowNum) -> row.getString(0));
Flux<String> lastNames = reactiveCqlTemplate.query(
		session -> session.prepare("SELECT last_name FROM t_actor WHERE id = ?"),
		ps -> ps.bind(1212L),
		(row, rowNum) -> row.getString(0));

Spring Data Cassandra 在 cql 包中提供了支持该模式的类:spring-doc.cadn.net.cn

  • SimplePreparedStatementCreator - 用于创建预编译语句的工具类。spring-doc.cadn.net.cn

  • ArgumentPreparedStatementBinder - 用于将参数绑定到预编译语句(prepared statement)的工具类。spring-doc.cadn.net.cn

使用CassandraTemplate

CassandraTemplate 类构建于 CqlTemplate 之上,提供了更高层次的抽象。 可以通过调用 CassandraTemplatesetUsePreparedStatements(false) 直接在 setUsePreparedStatements(true)(及其异步和响应式变体)上控制是否使用预编译语句。 请注意,CassandraTemplate 默认启用预编译语句。spring-doc.cadn.net.cn

以下示例展示了生成和接受 CQL 的方法的使用:spring-doc.cadn.net.cn

template.setUsePreparedStatements(true);

Actor actorByQuery = template.selectOne(query(where("id").is(42)), Actor.class);

Actor actorByStatement = template.selectOne(
		SimpleStatement.newInstance("SELECT id, name FROM actor WHERE id = ?", 42),
		Actor.class);
template.setUsePreparedStatements(true);

Mono<Actor> actorByQuery = template.selectOne(query(where("id").is(42)), Actor.class);

Mono<Actor> actorByStatement = template.selectOne(
		SimpleStatement.newInstance("SELECT id, name FROM actor WHERE id = ?", 42),
		Actor.class);

调用诸如 select(Query, Class<T>)update(Query, Update, Class<T>) 等绑定实体的方法时,会自行构建 CQL 语句以执行预期的操作。 某些 CassandraTemplate 方法(例如 select(Statement<?>, Class<T>))在其 API 中也接受 CQL Statement 对象。spring-doc.cadn.net.cn

在调用接受 Statement 参数的方法时,如果传入的是 SimpleStatement 对象,则可以参与预编译语句(prepared statements)的执行。 模板 API 会提取查询字符串和参数(包括位置参数和命名参数),并使用这些信息来预编译、绑定并执行该语句。 非 SimpleStatement 对象无法用于预编译语句。spring-doc.cadn.net.cn

缓存预编译语句

从 Cassandra 驱动程序 4.0 版本开始,预编译语句(prepared statements)由 CqlSession 缓存,因此重复准备相同的字符串是安全的。 在早期版本中,需要在驱动程序外部对预编译语句进行缓存。 更多详情请参阅驱动程序关于预编译语句的文档spring-doc.cadn.net.cn