10.7.保存、更新和删除行
ReactiveCassandraTemplate 为您提供了一种简单的方法来保存、更新和删除域对象并将这些对象映射到 Cassandra 中管理的表。
10.7.1.插入和更新行的方法
CassandraTemplate有几种方便的方法来保存和插入您的对象。要对转换过程进行更细粒度的控制,您可以Converter使用MappingCassandraConverter (例如,Converter<Row, Person>)注册 Spring实例。
插入和更新操作的区别在于INSERT操作不插入null值。
使用该INSERT操作的简单案例是保存一个 POJO。在这种情况下,表名由简单的类名(而不是完全限定的类名)确定。可以使用映射元数据覆盖存储对象的表。
插入或更新时,id必须设置该属性。Apache Cassandra 无法生成 ID。
以下示例使用保存操作并检索其内容:
示例 67. 使用 CassandraTemplate
代码语言:javascript复制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);
您可以使用以下操作进行插入和保存:
- void insert (Object objectToSave):在 Apache Cassandra 表中插入对象。
- WriteResult 插入 (Object objectToSave, InsertOptions options):在 Apache Cassandra 表中插入对象并应用InsertOptions。
您可以使用以下更新操作:
- void update (Object objectToSave):更新 Apache Cassandra 表中的对象。
- WriteResult 更新 (Object objectToSave, UpdateOptions options):更新 Apache Cassandra 表中的对象并应用UpdateOptions。
您还可以使用老式的方式编写自己的 CQL 语句,如下例所示:
代码语言:javascript复制String cql = "INSERT INTO person (age, name) VALUES (39, 'Bob')";
Mono<Boolean> applied = reactiveCassandraTemplate.getReactiveCqlOperations().execute(cql);
您还可以在使用InsertOptions和时配置其他选项,例如 TTL、一致性级别和轻量级事务UpdateOptions。
我的行插入到哪个表中?
您可以通过两种方式管理用于对表进行操作的表名。默认表名是更改为以小写字母开头的简单类名。因此,com.example.Person类的一个实例将存储在person表中。第二种方式是在@Table注解中指定表名。
10.7.2.更新表中的行
对于更新,您可以选择更新多行。
以下示例显示了通过向具有 分配的余额添加一次性 50.00 美元奖金来更新单个帐户对象:
示例 68. 使用更新行 ReactiveCasandraTemplate
代码语言:javascript复制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班有匹配可用的Apache Cassandra的更新任务,从而方法。
大多数方法返回Update对象以提供用于代码样式目的的流畅 API。
有关更多详细信息,请参阅“为行执行更新的方法”。
11. Cassandra 存储库
本章涵盖了对 Apache Cassandra 的 Spring Data Repository 支持的详细信息。Cassandra 的存储库支持建立在“使用 Spring 数据存储库”中解释的核心存储库支持之上。Cassandra 存储库将CassandraTemplate其CqlTemplate用作基础设施 bean。在继续之前,您应该了解那里解释的基本概念。
11.1.用法
要访问存储在 Apache Cassandra 中的域实体,您可以使用 Spring Data 复杂的存储库支持,这大大简化了 DAO 的实现。为此,请为您的存储库创建一个接口,如以下示例所示:
示例 69. 示例 Person 实体
代码语言:javascript复制@Table
public class Person {
@Id
private String id;
private String firstname;
private String lastname;
// … getters and setters omitted
}
请注意,该实体有一个名为idtype的属性String。中使用的默认序列化机制CassandraTemplate(支持存储库支持)将命名的属性id视为行 ID。
以下示例显示了用于持久化Person实体的存储库定义:
示例 70. 用于持久化Person实体的基本存储库接口
代码语言:javascript复制public interface PersonRepository extends CrudRepository<Person, String> {
// additional custom finder methods go here
}
目前,前面示例中的接口仅用于键入目的,但稍后我们会向其添加其他方法。
接下来,在您的 Spring 配置中,添加以下内容(如果您使用 Java 进行配置):
如果要使用 Java 配置,请使用@ EnableCassandraRepositories注解。注释带有与命名空间元素相同的属性。如果没有配置基础包,基础设施会扫描带注释的配置类的包。下面的例子展示了如何使用@EnableCassandraRepositories注解:
示例 71. 存储库的 Java 配置
代码语言:javascript复制@Configuration
@EnableCassandraRepositories
class ApplicationConfig extends AbstractCassandraConfiguration {
@Override
protected String getKeyspaceName() {
return "keyspace";
}
public String[] getEntityBasePackages() {
return new String[] { "com.oreilly.springdata.cassandra" };
}
}
如果您想使用 XML 配置,那么以下示例显示了一个最小的配置片段:
示例 72.Cassandra 存储库 Spring XML 配置
代码语言:javascript复制<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:cassandra="http://www.springframework.org/schema/data/cassandra"
xsi:schemaLocation="
http://www.springframework.org/schema/data/cassandra
https://www.springframework.org/schema/data/cassandra/spring-cassandra.xsd
http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<cassandra:session port="9042" keyspace-name="keyspaceName"/>
<cassandra:mapping
entity-base-packages="com.acme.*.entities">
</cassandra:mapping>
<cassandra:converter/>
<cassandra:template/>
<cassandra:repositories base-package="com.acme.*.entities"/>
</beans>
的cassandra:repositories命名空间元素使得用于扩展接口将被扫描的基本包CrudRepository为每一个发现,创建弹簧豆。默认情况下,存储库与一个CassandraTemplate名为的Spring bean 连接cassandraTemplate,因此cassandra-template-ref如果您偏离此约定,您只需显式配置 。
因为我们的域存储库扩展了CrudRepository,它为您提供了基本的 CRUD 操作。使用存储库实例是将存储库作为依赖项注入客户端的问题,如以下示例通过自动装配所做的PersonRepository:
示例 73. 对 Person 实体的基本访问
代码语言:javascript复制@RunWith(SpringRunner.class)
@ContextConfiguration
public class PersonRepositoryTests {
@Autowired PersonRepository repository;
@Test
public void readsPersonTableCorrectly() {
List<Person> persons = repository.findAll();
assertThat(persons.isEmpty()).isFalse();
}
}
Cassandra 存储库支持对实体进行分页和排序访问的分页和排序。Cassandra 分页需要分页状态才能向前浏览页面。ASlice跟踪当前的分页状态并允许创建一个Pageable请求下一页。以下示例显示如何设置对Person实体的分页访问:
示例 74. 对Person实体的分页访问
代码语言:javascript复制@RunWith(SpringRunner.class)
@ContextConfiguration
public class PersonRepositoryTests {
@Autowired PersonRepository repository;
@Test
public void readsPagesCorrectly() {
Slice<Person> firstBatch = repository.findAll(CassandraPageRequest.first(10));
assertThat(firstBatch).hasSize(10);
Page<Person> nextBatch = repository.findAll(firstBatch.nextPageable());
// …
}
}
Cassandra 存储库不扩展 PagingAndSortingRepository,因为使用限制/偏移的经典分页模式不适用于 Cassandra。
前面的示例使用 Spring 的单元测试支持创建了一个应用程序上下文,它执行基于注解的依赖注入到测试类中。在测试用例(测试方法)中,我们使用存储库来查询数据存储。我们调用请求所有Person实例的存储库查询方法。
11.2.查询方法
您通常在存储库上触发的大多数数据访问操作都会导致对 Apache Cassandra 数据库执行查询。定义这样的查询就是在存储库接口上声明一个方法。以下示例显示了许多此类方法声明:
示例 75.带有查询方法的 PersonRepository
代码语言:javascript复制public interface PersonRepository extends CrudRepository<Person, String> {
List<Person> findByLastname(String lastname);
Slice<Person> findByFirstname(String firstname, Pageable pageRequest);
List<Person> findByFirstname(String firstname, QueryOptions opts);
List<Person> findByFirstname(String firstname, Sort sort);
Person findByShippingAddress(Address address);
Person findFirstByShippingAddress(Address address);
Stream<Person> findAllBy();
@AllowFiltering
List<Person> findAllByAge(int age);
}
该方法显示了对所有具有给定 的人的查询lastname。查询源自解析约束的方法名称,可以与And. 因此,方法名称导致查询表达式为SELECT * FROM person WHERE lastname = 'lastname'。
将分页应用于查询。您可以为您的方法签名配备一个Pageable参数,并让该方法返回一个Slice实例,我们会相应地自动分页查询。
传递QueryOptions对象在执行之前将查询选项应用于结果查询。
对查询应用动态排序。您可以Sort向方法签名添加参数,Spring Data 会自动将排序应用于查询。
表明您可以使用 中Converter注册的实例基于非原始类型的属性进行查询CustomConversions。 IncorrectResultSizeDataAccessException如果找到多个匹配项,则抛出。
使用First关键字将查询限制为仅第一个结果。与前面的方法不同,如果找到多个匹配项,则此方法不会引发异常。
Stream在迭代流时使用 Java 8读取和转换单个元素。
显示带有@AllowFiltering,注释的查询方法,以允许服务器端过滤。
查询非主键属性需要二级索引。
下表显示了可以在查询方法中使用的关键字的简短示例: