|
此版本仍在开发中,尚未被视为稳定版本。如需最新稳定版本,请使用 Spring Data Cassandra 5.0.4! |
CQL 模板 API
CqlTemplate 类(及其响应式变体 ReactiveCqlTemplate)是核心 CQL 包中的中心类。
它负责资源的创建和释放。
它执行核心 CQL 工作流的基本任务,例如语句的创建和执行,而将提供 CQL 和提取结果的任务留给应用程序代码。
CqlTemplate 类执行 CQL 查询和更新语句,对 ResultSet 实例进行迭代并提取返回的参数值。
它还捕获 CQL 异常,并将其转换为在 org.springframework.dao 包中定义的通用的、信息更丰富的异常层次结构。
当您为代码使用 CqlTemplate 时,只需实现具有明确定义契约的回调接口。
给定一个 CqlSession,PreparedStatementCreator 回调接口将使用提供的 CQL 和任何必要的参数创建一个 预编译语句。
RowCallbackHandler 接口从 ResultSet 的每一行中提取值。
The CqlTemplate 可以在 DAO 实现中通过直接使用 SessionFactory 引用实例化,也可以在 Spring 容器中配置并作为 Bean 引用传递给 DAO。CqlTemplate 是 CassandraTemplate 的基础构建块。
此类发出的所有 CQL 语句都会以 DEBUG 级别记录在与模板实例的全限定类名对应的日志类别下(通常为 CqlTemplate,但如果您使用了 CqlTemplate 类的自定义子类,则可能会有所不同)。
您可以通过在 CQL API 实例上配置以下参数来控制获取大小、一致性级别和重试策略的默认值:
CqlTemplate、AsyncCqlTemplate 和 ReactiveCqlTemplate。
如果未设置特定的查询选项,则应用默认值。
CqlTemplate 提供了不同的执行模型变体。
基础的 CqlTemplate 使用阻塞式执行模型。
你可以使用 AsyncCqlTemplate 进行异步执行,并通过 ListenableFuture 实例进行同步,
或者使用 ReactiveCqlTemplate 进行响应式执行。 |
示例CqlTemplate类用法
本节提供了一些 CqlTemplate 类的实际使用示例。
这些示例并未涵盖 CqlTemplate 所提供的全部功能。
有关完整功能,请参阅Javadoc。
使用CqlTemplate
以下查询用于获取表中的行数:
-
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方法就可以引用该类。
例如,将上一段代码片段改写如下可能会更好:
-
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 操作。
参数值通常以可变参数的形式提供,或者也可以作为对象数组提供。
以下示例展示了如何使用 INSERT 执行 CqlTemplate 操作:
-
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");
以下示例展示了如何使用 UPDATE 执行 CqlTemplate 操作:
-
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);
以下示例展示了如何使用 DELETE 执行 CqlTemplate 操作:
-
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 语句。
它提供了大量重载版本,支持接受回调接口、绑定变量数组等参数。
以下示例展示了如何使用传递给 execute() 方法的不同 API 对象来创建和删除表:
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 通过 CqlSession 获取 Cassandra 的连接,该连接由 SessionFactory 提供。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 及其他 Template API 的实现类会在每次操作时获取一个 CqlSession。
由于会话具有较长的生命周期,因此在调用所需操作后不会关闭会话。
正确释放资源的责任在于使用该会话的容器或框架。
你可以在 SessionFactory 包中找到各种 org.springframework.data.cassandra.core.cql.session 的实现。
异常转换
Spring 框架为各种数据库和映射技术提供了异常转换功能。
传统上,这适用于 JDBC 和 JPA。
用于 Apache Cassandra 的 Spring Data 通过提供 org.springframework.dao.support.PersistenceExceptionTranslator 接口的实现,将此功能扩展到了 Apache Cassandra。
映射到 Spring 的一致的数据访问异常层次结构背后的动机,
是让你能够编写可移植且具有描述性的异常处理代码,而无需针对特定的 Cassandra 异常进行编码和处理。
Spring 所有的数据访问异常都继承自
DataAccessException 类,因此你可以确信,只需在一个 try-catch 块中就能捕获所有与数据库相关的异常。
ReactiveCqlTemplate 和 ReactiveCassandraTemplate 会尽早传播异常。
在响应式序列处理过程中发生的异常会作为错误信号发出。