CQL 模板 API
CqlTemplate 类(及其反应式变体 ReactiveCqlTemplate)是核心 CQL 包中的核心类。它处理资源的创建和释放。它执行核心 CQL 工作流的基本任务,例如语句的创建和执行,并将 CQL 的提供和结果的提取留给应用程序代码。CqlTemplate
类执行 CQL 查询和更新语句,执行对 ResultSet
实例的迭代并提取返回的参数值。它还捕获 CQL 异常并将其转换为 org.springframework.dao
包中定义的通用、更具信息性的异常层次结构。
当你在代码中使用 CqlTemplate
时,只需要实现回调接口,这些接口有明确的契约。给定一个 CqlSession
,PreparedStatementCreator 回调接口使用提供的 CQL 和任何必要的参数创建一个 预处理语句。RowCallbackHandler 接口从 ResultSet
的每一行中提取值。
CqlTemplate 可以通过直接实例化与 SessionFactory 引用在 DAO 实现中使用,或者在 Spring 容器中配置并作为 bean 引用提供给 DAO。CqlTemplate
是 CassandraTemplate 的基础构建块。
此类发出的所有 CQL 都会以 DEBUG
级别记录在对应于模板实例的完全限定类名的类别下(通常是 CqlTemplate
,但如果使用了 CqlTemplate
类的自定义子类,可能会有所不同)。
你可以通过在 CQL API 实例上配置以下参数来控制获取大小、一致性级别和重试策略的默认值:CqlTemplate、AsyncCqlTemplate 和 ReactiveCqlTemplate。如果未设置特定的查询选项,将应用默认值。
CqlTemplate
有不同的执行模型。基本的 CqlTemplate
使用阻塞执行模型。您可以使用 AsyncCqlTemplate
进行异步执行,并与 ListenableFuture
实例同步,或者使用 ReactiveCqlTemplate
进行响应式执行。
CqlTemplate
类用法示例
本节提供了一些 CqlTemplate
类的使用示例。这些示例并不是 CqlTemplate
所暴露的所有功能的完整列表。有关完整功能,请参阅 Javadoc。
使用 CqlTemplate
进行查询(SELECT)
以下查询获取表中的行数:
- Imperative
- Reactive
int rowCount = cqlTemplate.queryForObject("SELECT COUNT(*) FROM t_actor", Integer.class);
Mono<Integer> rowCount = reactiveCqlTemplate.queryForObject("SELECT COUNT(*) FROM t_actor", Integer.class);
以下查询使用了绑定变量:
- Imperative
- Reactive
int countOfActorsNamedJoe = cqlTemplate.queryForObject(
"SELECT COUNT(*) FROM t_actor WHERE first_name = ?", Integer.class, "Joe");
Mono<Integer> countOfActorsNamedJoe = reactiveCqlTemplate.queryForObject(
"SELECT COUNT(*) FROM t_actor WHERE first_name = ?", Integer.class, "Joe");
以下示例查询一个 String
:
- 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);
以下示例查询并填充单个域对象:
- Imperative
- Reactive
Actor actor = cqlTemplate.queryForObject("SELECT first_name, last_name FROM t_actor WHERE id = ?",
new RowMapper<Actor>() {
public Actor mapRow(Row row, int rowNum) {
Actor actor = new Actor();
actor.setFirstName(row.getString("first_name"));
actor.setLastName(row.getString("last_name"));
return actor;
}
}, 1212L);
Mono<Actor> actor = reactiveCqlTemplate.queryForObject(
"SELECT first_name, last_name FROM t_actor WHERE id = ?",
new RowMapper<Actor>() {
public Actor mapRow(Row row, int rowNum) {
Actor actor = new Actor();
actor.setFirstName(row.getString("first_name"));
actor.setLastName(row.getString("last_name"));
return actor;
}},
1212L);
以下示例查询并填充多个领域对象:
- Imperative
- Reactive
List<Actor> actors = cqlTemplate.query(
"SELECT first_name, last_name FROM t_actor",
new RowMapper<Actor>() {
public Actor mapRow(Row row, int rowNum) {
Actor actor = new Actor();
actor.setFirstName(row.getString("first_name"));
actor.setLastName(row.getString("last_name"));
return actor;
}
});
Flux<Actor> actors = reactiveCqlTemplate.query(
"SELECT first_name, last_name FROM t_actor",
new RowMapper<Actor>() {
public Actor mapRow(Row row, int rowNum) {
Actor actor = new Actor();
actor.setFirstName(row.getString("first_name"));
actor.setLastName(row.getString("last_name"));
return actor;
}
});
如果最后两个代码片段实际上存在于同一个应用程序中,那么消除两个 RowMapper
匿名内部类中存在的重复是有意义的,并将它们提取到一个单独的类中(通常是一个 static
嵌套类),然后可以在 DAO 方法中引用它。
# It might be better to write the last code snippet as follows:
def example_function():
# ... existing code ...
{{ edit_1 }} # Update the logic here
# ... existing code ...
{{ edit_2 }} # Add error handling
# ... existing code ...
In this example, I've indicated where to make updates to the code with comments. You can replace {{ edit_1 }}
and {{ edit_2 }}
with the specific changes you want to implement.
- Imperative
- Reactive
List<Actor> findAllActors() {
return cqlTemplate.query("SELECT first_name, last_name FROM t_actor", ActorMapper.INSTANCE);
}
enum ActorMapper implements RowMapper<Actor> {
INSTANCE;
public Actor mapRow(Row row, int rowNum) {
Actor actor = new Actor();
actor.setFirstName(row.getString("first_name"));
actor.setLastName(row.getString("last_name"));
return actor;
}
}
Flux<Actor> findAllActors() {
return reactiveCqlTemplate.query("SELECT first_name, last_name FROM t_actor", ActorMapper.INSTANCE);
}
enum ActorMapper implements RowMapper<Actor> {
INSTANCE;
public Actor mapRow(Row row, int rowNum) {
Actor actor = new Actor();
actor.setFirstName(row.getString("first_name"));
actor.setLastName(row.getString("last_name"));
return actor;
}
}
INSERT
、UPDATE
和 DELETE
与 CqlTemplate
您可以使用 execute(…)
方法执行 INSERT
、UPDATE
和 DELETE
操作。参数值通常作为可变参数提供,或者作为对象数组提供。
以下示例展示了如何使用 CqlTemplate
执行 INSERT
操作:
- Imperative
- Reactive
cqlTemplate.execute(
"INSERT INTO t_actor (first_name, last_name) VALUES (?, ?)",
"Leonor", "Watling");
Mono<Boolean> applied = reactiveCqlTemplate.execute(
"INSERT INTO t_actor (first_name, last_name) VALUES (?, ?)",
"Leonor", "Watling");
以下示例演示了如何使用 CqlTemplate
执行 UPDATE
操作:
- Imperative
- Reactive
cqlTemplate.execute(
"UPDATE t_actor SET last_name = ? WHERE id = ?",
"Banjo", 5276L);
Mono<Boolean> applied = reactiveCqlTemplate.execute(
"UPDATE t_actor SET last_name = ? WHERE id = ?",
"Banjo", 5276L);
以下示例展示了如何使用 CqlTemplate
执行 DELETE
操作:
- Imperative
- Reactive
cqlTemplate.execute(
"DELETE FROM t_actor WHERE id = ?",
5276L);
Mono<Boolean> applied = reactiveCqlTemplate.execute(
"DELETE FROM actor WHERE id = ?",
actorId);
其他 CqlTemplate
操作
你可以使用 execute(..)
方法来执行任何任意的 CQL。因此,该方法通常用于 DDL 语句。它有许多重载版本,支持回调接口、绑定变量数组等。
以下示例演示了如何使用不同的 API 对象通过 execute()
方法创建和删除表:
cqlTemplate.execute("CREATE TABLE test_table (id uuid primary key, event text)");
DropTableSpecification dropper = DropTableSpecification.dropTable("test_table");
String cql = DropTableCqlGenerator.toCql(dropper);
cqlTemplate.execute(cql);
控制 Cassandra 连接
应用程序通过使用 CqlSession
对象连接到 Apache Cassandra。一个 Cassandra CqlSession
会跟踪与各个节点的多个连接,并且设计为线程安全、长期存在的对象。通常,您可以为整个应用程序使用一个 CqlSession
。
Spring 通过 SessionFactory
获取 Cassandra 的 CqlSession
。SessionFactory
是 Spring Data for Apache Cassandra 的一部分,是一个通用的连接工厂。它使容器或框架能够将连接处理和路由问题隐藏在应用程序代码之外。
以下示例展示了如何配置默认的 SessionFactory
:
- Imperative
- Reactive
CqlSession session = … // get a Cassandra Session
CqlTemplate template = new CqlTemplate();
template.setSessionFactory(new DefaultSessionFactory(session));
CqlSession session = … // get a Cassandra Session
ReactiveCqlTemplate template = new ReactiveCqlTemplate(new DefaultBridgedReactiveSession(session));
CqlTemplate
和其他模板 API 实现会为每个操作获取一个 CqlSession
。由于其长期存在的特性,操作完成后会保持会话打开,直到需要时才关闭。正确的资源处置责任由使用该会话的容器或框架承担。
你可以在 org.springframework.data.cassandra.core.cql.session
包中找到各种 SessionFactory
实现。
异常翻译
Spring 框架为各种数据库和映射技术提供了异常转换。这通常适用于 JDBC 和 JPA。Spring Data for Apache Cassandra 通过提供 org.springframework.dao.support.PersistenceExceptionTranslator
接口的实现,将此功能扩展到 Apache Cassandra。
映射到 Spring 的一致的数据访问异常层次结构的动机是让你能够编写可移植且具有描述性的异常处理代码,而无需针对和处理特定的 Cassandra 异常。Spring 的所有数据访问异常都继承自 DataAccessException
类,因此你可以确信可以在一个单一的 try-catch 块中捕获所有与数据库相关的异常。
ReactiveCqlTemplate
和 ReactiveCassandraTemplate
尽早传播异常。在处理反应序列期间发生的异常会作为错误信号发出。