此版本仍在开发中,尚未被视为稳定版本。对于最新的稳定版本,请使用 Spring Data Cassandra 4.4.0! |
持久化实体
这CassandraTemplate
class 及其响应式变体ReactiveCassandraTemplate
),位于org.springframework.data.cassandra
package 是 Spring 的 Cassandra 支持中的中心类,它提供了丰富的功能集来与数据库交互。
该模板提供了用于创建、更新、删除和查询 Cassandra 的便捷作,并在 Cassandra 表中提供域对象和行之间的映射。
配置后,模板实例是线程安全的,并且可以在多个实例之间重复使用。 |
Cassandra 中的行与应用程序域类之间的映射是通过委托给CassandraConverter
接口。
Spring 提供了一个默认的实现MappingCassandraConverter
,但您也可以编写自己的自定义转换器。
请参阅 Cassandra 转换 部分 以了解更多详细信息。
这CassandraTemplate
类实现CassandraOperations
interface 及其响应式变体ReactiveCassandraTemplate
实现ReactiveCassandraOperations
.
尽可能地使用[Reactive]CassandraOperations
以 Cassandra 中可用的方法命名,以使已经熟悉 Cassandra 的开发人员熟悉 API。
例如,您可以找到select
,insert
,delete
和update
.
设计目标是尽可能轻松地在基本 Cassandra 驱动程序和[Reactive]CassandraOperations
.
这两个 API 之间的主要区别在于CassandraOperations
可以传递域对象,而不是 CQL 和 query 对象。
在[Reactive]CassandraTemplate 实例通过[Reactive]CassandraOperations 接口。 |
使用的默认转换器实现[Reactive]CassandraTemplate
是MappingCassandraConverter
.
而MappingCassandraConverter
可以使用其他元数据来指定对象到行的映射,它还可以通过使用一些约定进行字段和表名的映射来转换不包含其他元数据的对象。
这些约定以及映射注释的使用将在 “映射” 一章中解释。
另一个核心特征[Reactive]CassandraTemplate
是将 Cassandra Java 驱动程序中引发的异常转换为 Spring 的可移植数据访问异常层次结构。
请参阅 异常转换 以了解更多信息。
模板 API 具有不同的执行模型风格。
基本的CassandraTemplate 使用阻塞 (命令同步) 执行模型。
您可以使用AsyncCassandraTemplate 用于异步执行和同步ListenableFuture instances 或ReactiveCassandraTemplate 进行响应式执行。 |
实例化CassandraTemplate
CassandraTemplate
应该始终配置为 Spring bean,尽管我们前面展示了一个可以直接实例化它的示例。
但是,由于我们假设了创建 Spring 模块的上下文,因此我们假设存在 Spring 容器。
有两种方法可以获取CassandraTemplate
,具体取决于您加载 Spring 的方式ApplicationContext
:
自动装配
您可以自动装配[Reactive]CassandraOperations
添加到您的项目中,如下例所示:
-
Imperative
-
Reactive
@Autowired
private CassandraOperations cassandraOperations;
@Autowired
private ReactiveCassandraOperations reactiveCassandraOperations;
与所有 Spring 自动装配一样,这假设只有一个类型的 bean[Reactive]CassandraOperations
在ApplicationContext
.
如果您有多个[Reactive]CassandraTemplate
bean(如果在同一项目中使用多个 keyspace),则可以使用@Qualifier
注解来指定要自动装配的 Bean。
-
Imperative
-
Reactive
@Autowired
@Qualifier("keyspaceOneTemplateBeanId")
private CassandraOperations cassandraOperations;
@Autowired
@Qualifier("keyspaceOneTemplateBeanId")
private ReactiveCassandraOperations reactiveCassandraOperations;
Bean 查找ApplicationContext
您还可以查找[Reactive]CassandraTemplate
bean 的ApplicationContext
,如以下示例所示:
-
Imperative
-
Reactive
CassandraOperations cassandraOperations = applicationContext.getBean("cassandraTemplate", CassandraOperations.class);
ReactiveCassandraOperations cassandraOperations = applicationContext.getBean("ReactiveCassandraOperations", ReactiveCassandraOperations.class);
查询行
您可以使用Query
和Criteria
类,这些类具有反映本机 Cassandra 谓词运算符名称的方法名称,例如lt
,lte
,is
等。
这Query
和Criteria
类遵循 Fluent API 样式,因此您可以轻松地将多个方法标准和查询链接在一起,同时拥有易于理解的代码。
在 Java 中创建时,使用 Static importsQuery
和Criteria
实例来提高可读性。
查询表中的行
在前面的部分中,我们了解了如何使用selectOneById
method 开启[Reactive]CassandraTemplate
.
这样做将返回单个域对象。
我们还可以查询要作为域对象列表返回的行集合。
假设我们有大量的Person
名称 (name) 和 年龄 (age) 值作为行存储在表中的对象,并且每个人都有账户余额,那么我们现在可以使用以下代码运行查询:
[Reactive]CassandraTemplate
-
Imperative
-
Reactive
import static org.springframework.data.cassandra.core.query.Criteria.where;
import static org.springframework.data.cassandra.core.query.Query.query;
…
List<Person> result = cassandraTemplate.select(query(where("age").is(50))
.and(where("balance").gt(1000.00d)).withAllowFiltering(), Person.class);
import static org.springframework.data.cassandra.core.query.Criteria.where;
import static org.springframework.data.cassandra.core.query.Query.query;
…
Flux<Person> result = reactiveCassandraTemplate.select(query(where("age").is(50))
.and(where("balance").gt(1000.00d)).withAllowFiltering(), Person.class);
这select
,selectOne
和stream
方法采用Query
object 作为参数。
此对象定义用于执行查询的条件和选项。
该条件通过使用Criteria
对象,该对象具有名为where
这会实例化一个新的Criteria
对象。
我们建议对org.springframework.data.cassandra.core.query.Criteria.where
和Query.query
,使查询更具可读性。
此查询应返回Person
满足指定条件的对象。
这Criteria
class 具有以下方法,这些方法对应于 Apache Cassandra 中提供的运算符:
Criteria 类的方法
-
CriteriaDefinition
燃气轮机(Object value)
:使用运算符创建标准。>
-
CriteriaDefinition
GTE(Object value)
:使用运算符创建标准。>=
-
CriteriaDefinition
在(Object… values)
:使用IN
运算符。 -
CriteriaDefinition
在(Collection<?> collection)
:使用IN
运算符。 -
CriteriaDefinition
是(Object value)
:使用字段匹配 (column = value
). -
CriteriaDefinition
中尉(Object value)
:使用运算符创建标准。<
-
CriteriaDefinition
LTE(Object value)
:使用⇐
算子。 -
CriteriaDefinition
喜欢(Object value)
:使用LIKE
算子。 -
CriteriaDefinition
包含(Object value)
:使用CONTAINS
算子。 -
CriteriaDefinition
containsKey(Object key)
:使用CONTAINS KEY
算子。
Criteria
一旦创建,就不可变。
Query 类的方法
这Query
class 具有一些其他方法,您可以使用这些方法为查询提供选项:
-
Query
由(CriteriaDefinition… criteria)
:用于创建Query
对象。 -
Query
和(CriteriaDefinition criteria)
:用于向查询添加其他条件。 -
Query
列(Columns columns)
:用于定义要包含在查询结果中的列。 -
Query
限制(Limit limit)
:用于将返回结果的大小限制为提供的限制(使用SELECT
限制)。 -
Query
限制(long limit)
:用于将返回结果的大小限制为提供的限制(使用SELECT
限制)。 -
Query
page请求(Pageable pageRequest)
:用于关联Sort
,PagingState
和fetchSize
替换为查询 (用于分页)。 -
Query
pagingState(ByteBuffer pagingState)
:用于将ByteBuffer
替换为查询 (用于分页)。 -
Query
queryOptions 查询选项(QueryOptions queryOptions)
:用于关联QueryOptions
替换为查询。 -
Query
排序(Sort sort)
:用于为结果提供排序定义。 -
Query
withAllowFiltering :用于渲染()
ALLOW FILTERING
查询。
Query
一旦创建,就不可变。
调用方法创建新的不可变 (中间)Query
对象。
查询行的方法
这Query
class 具有以下返回 rows 的方法:
-
List<T>
选择(Query query, Class<T> entityClass)
:查询T
从表中。 -
T
选择一(Query query, Class<T> entityClass)
:查询T
从表中。 -
Slice<T>
片(Query query, Class<T> entityClass)
:通过查询Slice
类型的对象T
从表中。 -
Stream<T>
流(Query query, Class<T> entityClass)
:查询T
从表中。 -
List<T>
选择(String cql, Class<T> entityClass)
:对 type 为T
通过提供 CQL 语句从表中。 -
T
选择一(String cql, Class<T> entityClass)
:对T
通过提供 CQL 语句从表中。 -
Stream<T>
流(String cql, Class<T> entityClass)
:对T
通过提供 CQL 语句从表中。
查询方法必须指定目标类型T
,则返回。
Fluent 模板 API
这[Reactive]CassandraOperations
当涉及到 Apache Cassandra 的更多底层交互时,interface 是核心组件之一。
它提供了多种方法。
您可以找到每个方法的多个重载。
它们中的大多数涵盖了 API 的可选 (可为 null) 部分。
FluentCassandraOperations
及其反应式变体ReactiveFluentCassandraOperations
为常见的方法提供更窄的接口[Reactive]CassandraOperations
提供更易读、更流畅的 API。
入口点 (query(…)
,insert(…)
,update(…)
和delete(…)
) 遵循基于要执行的作的自然命名方案。
从入口点开始,API 旨在仅提供依赖于上下文的方法,这些方法将指导开发人员使用调用实际[Reactive]CassandraOperations
.
以下示例显示了 Fluent API:
-
Imperative
-
Reactive
List<SWCharacter> all = ops.query(SWCharacter.class)
.inTable("star_wars") (1)
.all();
1 | 如果出现以下情况,请跳过此步骤SWCharacter 定义表名@Table 或者,如果使用类名作为表名没有问题 |
Flux<SWCharacter> all = ops.query(SWCharacter.class)
.inTable("star_wars") (1)
.all();
1 | 如果出现以下情况,请跳过此步骤SWCharacter 定义表名@Table 或者,如果使用类名作为表名没有问题 |
如果 Cassandra 中的表包含不同类型的实体,例如Jedi
在 Table ofSWCharacters
,您可以使用不同的类型来映射查询结果。
您可以使用as(Class<?> targetType)
将结果映射到不同的目标类型,而query(Class<?> entityType)
仍然适用于查询和表名称。
以下示例使用query
和as
方法:
-
Imperative
-
Reactive
List<Jedi> all = ops.query(SWCharacter.class) (1)
.as(Jedi.class) (2)
.matching(query(where("jedi").is(true)))
.all();
1 | 查询字段将映射到SWCharacter 类型。 |
2 | 生成的行将映射到Jedi . |
Flux<Jedi> all = ops.query(SWCharacter.class) (1)
.as(Jedi.class) (2)
.matching(query(where("jedi").is(true)))
.all();
1 | 查询字段将映射到SWCharacter 类型。 |
2 | 生成的行将映射到Jedi . |
终止方法 (first()
,one()
,all()
和stream()
) 处理在检索单个实体和检索多个实体之间切换List
或Stream
和类似的作。
新的 Fluent 模板 API 方法(即query(..) ,insert(..) ,update(..) 和delete(..) ) 使用有效的线程安全支持对象来编写 CQL 语句。
但是,这是以额外的年轻一代 JVM 堆开销为代价的,因为该设计基于各种 CQL 语句组件的最终字段和更改构造。
在可能插入或删除大量对象时(例如,在循环内部),您应该小心。 |
保存、更新和删除行
[Reactive]CassandraTemplate
为您提供了一种简单的方法来保存、更新和删除域对象,并将这些对象映射到在 Cassandra 中托管的表。
插入和更新行的方法
[Reactive]CassandraTemplate
有几种保存和插入对象的便捷方法。
要对转换过程进行更精细的控制,您可以注册 SpringConverter
实例中具有MappingCassandraConverter
(例如,Converter<Row, Person>
).
插入和更新作之间的区别在于INSERT 作不插入null 值。 |
使用INSERT
作是保存一个 POJO。
在这种情况下,table 名由简单类名(而不是完全限定的类名)确定。
可以使用映射元数据覆盖用于存储对象的表。
插入或更新时,id
属性。
Apache Cassandra 无法生成 ID。
以下示例使用 save作并检索其内容:
[Reactive]CassandraTemplate
-
Imperative
-
Reactive
import static org.springframework.data.cassandra.core.query.Criteria.where;
import static org.springframework.data.cassandra.core.query.Query.query;
…
Person bob = new Person("Bob", 33);
cassandraTemplate.insert(bob);
Person queriedBob = cassandraTemplate.selectOneById(query(where("age").is(33)), Person.class);
import static org.springframework.data.cassandra.core.query.Criteria.where;
import static org.springframework.data.cassandra.core.query.Query.query;
…
Person bob = new Person("Bob", 33);
cassandraTemplate.insert(bob);
Mono<Person> queriedBob = reactiveCassandraTemplate.selectOneById(query(where("age").is(33)), Person.class);
您可以通过以下作进行 insert 和 save:
-
void
插入(Object objectToSave)
:将对象插入 Apache Cassandra 表中。 -
WriteResult
插入(Object objectToSave, InsertOptions options)
:将对象插入 Apache Cassandra 表中,并应用InsertOptions
.
您可以使用以下更新作:
-
void
更新(Object objectToSave)
:更新 Apache Cassandra 表中的对象。 -
WriteResult
更新(Object objectToSave, UpdateOptions options)
:更新 Apache Cassandra 表中的对象并应用UpdateOptions
.
您还可以使用老式方法编写自己的 CQL 语句,如下例所示:
-
Imperative
-
Reactive
String cql = "INSERT INTO person (age, name) VALUES (39, 'Bob')";
cassandraTemplate().getCqlOperations().execute(cql);
String cql = "INSERT INTO person (age, name) VALUES (39, 'Bob')";
Mono<Boolean> applied = reactiveCassandraTemplate.getReactiveCqlOperations().execute(cql);
您还可以在使用InsertOptions
和UpdateOptions
.
我的行插入到哪个表中?
您可以通过两种方式管理用于对表进行作的表名。
默认表名是更改为以小写字母开头的简单类名。
因此,一个com.example.Person
类将存储在person
桌子。
第二种方法是在@Table
注解。
在批处理中插入、更新和删除单个对象
Cassandra 协议支持使用批处理在一个作中插入行集合。
以下方法在[Reactive]CassandraTemplate
interface 支持此功能:
-
batchOps
:创建一个新的[Reactive]CassandraBatchOperations
以填充批处理。
[Reactive]CassandraBatchOperations
-
insert
:采用单个对象、数组 (var-args) 或Iterable
要插入的对象。 -
update
:采用单个对象、数组 (var-args) 或Iterable
要更新的对象数。 -
delete
:采用单个对象、数组 (var-args) 或Iterable
要删除的对象数。 -
withTimestamp
:将 TTL 应用于批处理。 -
execute
:执行批处理。
更新表中的行
对于更新,您可以选择更新多个行。
以下示例显示了通过向分配余额添加一次性 50.00 USD 奖金来更新单个账户对象:+
[Reactive]CasandraTemplate
-
Imperative
-
Reactive
import static org.springframework.data.cassandra.core.query.Criteria.where;
import org.springframework.data.cassandra.core.query.Query;
import org.springframework.data.cassandra.core.query.Update;
…
boolean applied = cassandraTemplate.update(Query.query(where("id").is("foo")),
Update.create().increment("balance", 50.00), Account.class);
import static org.springframework.data.cassandra.core.query.Criteria.where;
import org.springframework.data.cassandra.core.query.Query;
import org.springframework.data.cassandra.core.query.Update;
…
Mono<Boolean> wasApplied = reactiveCassandraTemplate.update(Query.query(where("id").is("foo")),
Update.create().increment("balance", 50.00), Account.class);
除了Query
前面讨论过,我们通过使用Update
对象。
这Update
class 具有与 Apache Cassandra 可用的更新分配匹配的方法。
大多数方法都会返回Update
object 提供用于代码样式设置的 Fluent API。
执行行更新的方法
update 方法可以更新行,如下所示:
-
boolean
更新(Query query, Update update, Class<?> entityClass)
:更新 Apache Cassandra 表中的选定对象。
Update 类的方法
这Update
class 可以与一点 “语法糖” 一起使用,因为它的方法应该链接在一起。
此外,您可以启动创建新的Update
实例替换为 static 方法public static Update update(String key, Object value)
以及使用静态导入。
这Update
class 具有以下方法:
-
AddToBuilder
addTo(String columnName)
AddToBuilder
入口点:-
更新
prepend(Object value)
:使用 update 分配将集合值添加到现有集合的前面。+
-
更新
prependAll(Object… values)
:使用 update 分配将所有集合值添加到现有集合的前面。+
-
更新
append(Object value)
:使用 update 分配将集合值附加到现有集合。+
-
更新
append(Object… values)
:使用 update 分配将所有集合值附加到现有集合。+
-
更新
entry(Object key, Object value)
:使用更新分配添加映射条目。+
-
更新
addAll(Map<? extends Object, ? extends Object> map)
:使用更新分配将所有映射条目添加到映射中。+
-
-
Update
删除(String columnName, Object value)
:使用 update 分配从集合中删除值。-
-
Update
Clear(String columnName)
:清除集合。 -
Update
增加(String columnName, Number delta)
:使用更新分配进行更新。+
-
Update
递减(String columnName, Number delta)
:使用更新分配进行更新。-
-
Update
设置(String columnName, Object value)
:使用更新分配进行更新。=
-
SetBuilder
设置(String columnName)
SetBuilder
入口点:-
更新
atIndex(int index).to(Object value)
:使用 update 赋值将给定索引处的集合设置为值。=
-
更新
atKey(String object).to(Object value)
:将给定键处的映射条目设置为更新分配的值。=
-
下面的清单显示了一些更新示例:
// UPDATE … SET key = 'Spring Data';
Update.update("key", "Spring Data")
// UPDATE … SET key[5] = 'Spring Data';
Update.empty().set("key").atIndex(5).to("Spring Data");
// UPDATE … SET key = key + ['Spring', 'DATA'];
Update.empty().addTo("key").appendAll("Spring", "Data");
请注意,Update
一旦创建,就不可变。
调用方法创建新的不可变 (中间)Update
对象。
删除行的方法
您可以使用以下重载方法从数据库中删除对象:
-
boolean
删除(Query query, Class<?> entityClass)
:删除Query
. -
T
删除(T entity)
:删除给定的对象。 -
T
删除(T entity, QueryOptions queryOptions)
:删除给定的对象QueryOptions
. -
boolean
删除ById(Object id, Class<?> entityClass)
:使用给定的 ID 删除对象。
乐观锁定
这@Version
annotation 提供类似于 Cassandra 上下文中的 JPA 语法,并确保更新仅应用于具有匹配版本的行。
Optimistic Locking 利用 Cassandra 的轻量级事务有条件地插入、更新和删除行。
因此INSERT
语句使用IF NOT EXISTS
条件。
对于更新和删除,version 属性的实际值将添加到UPDATE
条件,如果另一个作同时更改了该行,则修改不会产生任何影响。
在这种情况下,一个OptimisticLockingFailureException
被抛出。
以下示例显示了这些功能:
@Table
class Person {
@Id String id;
String firstname;
String lastname;
@Version Long version;
}
Person daenerys = template.insert(new Person("Daenerys")); (1)
Person tmp = template.findOne(query(where("id").is(daenerys.getId())), Person.class); (2)
daenerys.setLastname("Targaryen");
template.save(daenerys); (3)
template.save(tmp); // throws OptimisticLockingFailureException (4)
1 | 最初插入文档。version 设置为0 . |
2 | 加载刚刚插入的文档。version 仍然0 . |
3 | 使用version = 0 .
将lastname 和 bumpversion 自1 . |
4 | 尝试更新之前加载的文档,该文档仍然具有version = 0 .
作失败,并显示OptimisticLockingFailureException ,作为当前version 是1 . |
Optimistic Locking 仅支持单实体作,不支持批处理作。 |