For the latest stable version, please use Spring Data Cassandra 4.4.0! |
Cassandra Repositories
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:
@Table
public class Person {
@Id
private String id;
private String firstname;
private String lastname;
// … getters and setters omitted
}
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.
The following example shows a repository definition to persist Person
entities:
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.
Next, in your Spring configuration, add the following (if you use Java for configuration):
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:
-
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" };
}
}
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.
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
:
-
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 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:
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 repositories do not extend PagingAndSortingRepository , because classic paging patterns using limit/offset are not applicable to Cassandra.
|
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’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 converts reactive wrapper types behind the scenes so that you can stick to your favorite composition library.