Cassandra Repositories

要访问存储在 Apache Cassandra 中的域实体,可以使用 Spring Data 复杂的存储库支持,这极大地简化了 DAO 的实现。要执行此操作,请为您的存储库创建一个接口,如下面的示例所示:

To access domain entities stored in Apache Cassandra, you can use Spring Data’s sophisticated repository support, which significantly eases implementing DAOs. To do so, create an interface for your repository, as the following example shows: .Sample Person entity

@Table
public class Person {

  @Id
  private String id;
  private String firstname;
  private String lastname;

  // … getters and setters omitted
}

请注意,实体有一个名为 id 的 String 类型的属性。MappingCassandraConverter 中使用的默认转换机制(它支持存储库支持)将名为 id 的属性视为行 ID。

Note that the entity has a property named id of type String. The default conversion mechanism used in MappingCassandraConverter (which backs the repository support) regards properties named id as being the row ID.

以下示例显示了一个存储 Person 实体的存储库定义:

The following example shows a repository definition to persist Person entities:

Basic repository interface to persist Person entities
  • Imperative

  • Reactive

interface PersonRepository extends CrudRepository<Person, String> {

  // additional custom finder methods go here
}
interface PersonRepository extends ReactiveCrudRepository<Person, String> {

  // additional custom finder methods go here
}

现在,前一个示例中的接口仅用作键入目的,但我们稍后会向其中添加其他方法。

Right now, the interface in the preceding example serves only typing purposes, but we add additional methods to it later.

接下来,在 Spring 配置中,如果使用 Java 进行配置,则添加以下内容:

Next, in your Spring configuration, add the following (if you use Java for configuration):

如果您想使用 Java 配置,请使用 @EnableCassandraRepositories 对应的 @EnableReactiveCassandraRepositories 注释。此注释具有与命名空间元素相同的属性。如果未配置基本包,基础架构将扫描带注释的配置类包。以下示例显示了如何使用不同的配置方法:

If you want to use Java configuration, use the @EnableCassandraRepositories respective @EnableReactiveCassandraRepositories annotation. The annotation carries the same attributes as the namespace element. If no base package is configured, the infrastructure scans the package of the annotated configuration class. The following example show how to the different configuration approaches:

Configuration for repositories
  • Imperative Java Configuration

  • XML

  • Reactive Java Configuration

@Configuration
@EnableCassandraRepositories
class ApplicationConfig extends AbstractCassandraConfiguration {

  @Override
  protected String getKeyspaceName() {
    return "keyspace";
  }

  public String[] getEntityBasePackages() {
    return new String[] { "com.oreilly.springdata.cassandra" };
  }
}
<?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>
@Configuration
@EnableReactiveCassandraRepositories
class ApplicationConfig extends AbstractReactiveCassandraConfiguration {

  @Override
  protected String getKeyspaceName() {
    return "keyspace";
  }

  public String[] getEntityBasePackages() {
    return new String[] { "com.oreilly.springdata.cassandra" };
  }
}

cassandra:repositories 命名空间元素导致扫描基本包以查找扩展 CrudRepository 的接口,并为找到的每个接口创建 Spring bean。默认情况下,存储库会通过称为 cassandraTemplateCassandraTemplate Spring bean 进行连接,因此只有当偏离此约定时才需要明确配置 cassandra-template-ref

The cassandra:repositories namespace element causes the base packages to be scanned for interfaces that extend CrudRepository and create Spring beans for each one found. By default, the repositories are wired with a CassandraTemplate Spring bean called cassandraTemplate, so you only need to configure cassandra-template-ref explicitly if you deviate from this convention.

因为我们的域存储库扩展了 CrudRepository 对应的 ReactiveCrudRepository,所以它会为您提供基本的 CRUD 操作。处理存储库实例只是将存储库作为依赖项注入到客户端,如下面的示例通过自动连接 PersonRepository 所示:

Because our domain repository extends CrudRepository respective ReactiveCrudRepository, it provides you with basic CRUD operations. Working with the repository instance is a matter of injecting the repository as a dependency into a client, as the following example does by autowiring PersonRepository:

Basic access to Person entities
  • Imperative

  • Reactive

@ExtendWith(SpringExtension.class)
class PersonRepositoryTests {

    @Autowired PersonRepository repository;

    @Test
    void readsPersonTableCorrectly() {

      List<Person> persons = repository.findAll();
      assertThat(persons.isEmpty()).isFalse();
    }
}
public class PersonRepositoryTests {

    @Autowired ReactivePersonRepository repository;

    @Test
    public void sortsElementsCorrectly() {
        Flux<Person> people = repository.findAll(Sort.by(new Order(ASC, "lastname")));
    }
}

Cassandra 存储库支持分页和排序,以便对实体进行分页和排序的访问。Cassandra 分页需要分页状态才能在页间进行仅转发导航。Slice 跟踪当前分页状态并允许创建 Pageable 来请求下一页。以下示例显示如何设置对 Person 实体的分页访问:

Cassandra repositories support paging and sorting for paginated and sorted access to the entities. Cassandra paging requires a paging state to forward-only navigate through pages. A Slice keeps track of the current paging state and allows for creation of a Pageable to request the next page. The following example shows how to set up paging access to Person entities:

Paging access to Person entities
  • Imperative

  • Reactive

@ExtendWith(SpringExtension.class)
class PersonRepositoryTests {

    @Autowired PersonRepository repository;

    @Test
    void readsPagesCorrectly() {

      Slice<Person> firstBatch = repository.findAll(CassandraPageRequest.first(10));

      assertThat(firstBatch).hasSize(10);

      Slice<Person> nextBatch = repository.findAll(firstBatch.nextPageable());

      // …
    }
}
@ExtendWith(SpringExtension.class)
class PersonRepositoryTests {

    @Autowired PersonRepository repository;

    @Test
    void readsPagesCorrectly() {

      Mono<Slice<Person>> firstBatch = repository.findAll(CassandraPageRequest.first(10));

      Mono<Slice<Person>> nextBatch = firstBatch.flatMap(it -> repository.findAll(it.nextPageable()));

      // …
    }
}}

Cassandra 存储库不扩展 PagingAndSortingRepository,因为使用 limit/offset 的经典分页模式不适用于 Cassandra。

Cassandra repositories do not extend PagingAndSortingRepository, because classic paging patterns using limit/offset are not applicable to Cassandra.

前一个示例使用 Spring 的单元测试支持创建应用程序上下文,它将基于注释的依赖项注入到测试类中。在测试用例中(测试方法),我们使用存储库查询数据存储。我们调用存储库查询方法,请求所有 Person 实例。

The preceding example creates an application context with Spring’s unit test support, which performs annotation-based dependency injection into the test class. Inside the test cases (the test methods), we use the repository to query the data store. We invoke the repository query method that requests all Person instances.

Reactive Repositories

Spring Data 的存储库抽象是一种动态 API,大部分由您和您的要求定义,因为您声明查询方法。通过扩展库特定存储库接口之一,可以使用 RxJava 或 Project Reactor 包装器类型实现 Reactive Cassandra 存储库:

Spring Data’s repository abstraction is a dynamic API that is mostly defined by you and your requirements as you declare query methods. Reactive Cassandra repositories can be implemented by using either RxJava or Project Reactor wrapper types by extending from one of the library-specific repository interfaces:

  • ReactiveCrudRepository

  • ReactiveSortingRepository

  • RxJava3CrudRepository

  • RxJava3SortingRepository

Spring Data 在幕后转换反应式包装器类型,以便您可以坚持使用自己喜欢的组合库。

Spring Data converts reactive wrapper types behind the scenes so that you can stick to your favorite composition library.