Spring认证中国教育管理中心-Apache Cassandra 的 Spring 数据教程七

2021-12-15 15:07:17 浏览数 (1)

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,注释的查询方法,以允许服务器端过滤。

查询非主键属性需要二级索引。

下表显示了可以在查询方法中使用的关键字的简短示例:

0 人点赞