预处理语句
多次执行的 CQL 语句可以被预处理并存储在 PreparedStatement
对象中,以提高查询性能。驱动程序和 Cassandra 都维护 PreparedStatement
查询及其元数据的映射。你可以通过以下抽象来使用预处理语句:
-
通过选择 API 使用 CqlTemplate, AsyncCqlTemplate, 或 ReactiveCqlTemplate
-
通过启用预处理语句使用 CassandraTemplate, AsyncCassandraTemplate, 或 ReactiveCassandraTemplate
-
作为构建在 Template API 之上的 Cassandra 仓库
使用 CqlTemplate
CqlTemplate
类(及其异步和响应式变体)提供了多种方法,这些方法接受静态 CQL、Statement
对象和 PreparedStatementCreator
。接受静态 CQL 且没有额外参数的方法通常会直接执行 CQL 语句而不做进一步处理。接受静态 CQL 并结合参数数组的方法(如 execute(String cql, Object… args)
和 queryForRows(String cql, Object… args)
)使用预编译语句。在内部,这些方法会创建 PreparedStatementCreator
和 PreparedStatementBinder
对象来准备语句,并在后续将值绑定到语句上执行。Spring Data Cassandra 通常使用基于索引的参数绑定来处理预编译语句。
自 Cassandra 驱动程序版本 4 起,预编译语句在驱动程序级别进行缓存,从而不再需要在应用程序中跟踪预编译语句。
以下示例展示了如何使用参数化的预处理语句发出查询:
- Imperative
- Reactive
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);
在需要更好地控制语句准备和参数绑定的情况下(例如,使用命名绑定参数),您可以通过调用带有 PreparedStatementCreator
和 PreparedStatementBinder
参数的查询方法,完全控制预处理语句的创建和参数绑定:
- Imperative
- Reactive
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
包中:
-
SimplePreparedStatementCreator
- 工具类,用于创建预处理语句。 -
ArgumentPreparedStatementBinder
- 工具类,用于将参数绑定到预处理语句。
使用 CassandraTemplate
CassandraTemplate
类建立在 CqlTemplate
之上,提供了更高层次的抽象。可以通过调用 setUsePreparedStatements(false)
或相应的 setUsePreparedStatements(true)
直接在 CassandraTemplate
(以及其异步和响应式变体)上控制是否使用预处理语句。请注意,默认情况下,CassandraTemplate
会启用预处理语句的使用。
以下示例展示了生成和接受 CQL 的方法的使用:
- Imperative
- Reactive
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>)
)也接受 CQL Statement
对象作为其 API 的一部分。
可以在调用接受 Statement
的方法时,通过传入 SimpleStatement
对象来参与预编译语句。模板 API 提取查询字符串和参数(位置参数和命名参数),并使用这些信息来准备、绑定和执行语句。不能使用非 SimpleStatement
对象与预编译语句。
缓存预编译语句
自 Cassandra 驱动程序 4.0 以来,预编译语句由 CqlSession
缓存,因此可以安全地准备相同的字符串两次。以前的版本要求在驱动程序之外缓存预编译语句。有关更多信息,请参见 预编译语句的驱动程序文档。