Spring Data Cassandra简介

2023/05/18

1. 概述

本文是对使用Cassandra和Spring Data的实用介绍。

我们将从基础开始,通过配置和编码,最终构建一个完整的Spring Data Cassandra模块。

延伸阅读

使用Cassandra、Astra和Stargate构建仪表板

了解如何使用DataStax Astra构建仪表板,DataStax Astra是一种由Apache Cassandra和Stargate API提供支持的数据库即服务。

阅读更多

使用Cassandra、Astra、REST和GraphQL构建仪表板-记录状态更新

使用Cassandra存储时间序列数据的示例。

阅读更多

使用Cassandra、Astra和CQL构建仪表板-映射事件数据

了解如何根据存储在Astra数据库中的数据在交互式地图上显示事件。

阅读更多

2. Maven依赖

让我们从使用Maven在pom.xml中定义依赖关系开始:

<dependency>
    <groupId>com.datastax.cassandra</groupId>
    <artifactId>cassandra-driver-core</artifactId>
    <version>2.1.9</version>
</dependency>

3. Cassandra的配置

我们将在整个过程中使用Java风格的配置来配置Cassandra集成。

3.1 主要配置(Spring)

为此,我们将使用Java风格的配置。让我们从主配置类开始-当然是通过类级别的@Configuration注解驱动的:

@Configuration
public classCassandraConfig extends AbstractCassandraConfiguration {

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

    @Bean
    publicCassandraClusterFactoryBean cluster() {
        CassandraClusterFactoryBean cluster = newCassandraClusterFactoryBean();
        cluster.setContactPoints("127.0.0.1");
        cluster.setPort(9142);
        return cluster;
    }

    @Bean
    publicCassandraMappingContext cassandraMapping() throws ClassNotFoundException {
        return new BasicCassandraMappingContext();
    }
}

请注意新bean–BasicCassandraMappingContext具有默认实现。这是在对象和持久格式之间映射持久实体所必需的。

由于默认实现足够强大,我们可以直接使用它。

3.2 主要配置(Spring Boot)

让我们通过application.properties进行Cassandra配置:

spring.data.cassandra.keyspace-name=testKeySpace
spring.data.cassandra.port=9142
spring.data.cassandra.contact-points=127.0.0.1

我们完成了!这就是我们在使用Spring Boot时所需要的。

3.3 Cassandra连接属性

我们必须配置三个强制设置来为Cassandra客户端设置连接。

我们必须设置运行Cassandra服务器的主机名作为联系点。端口只是服务器中请求的监听端口。KeyspaceName是定义节点上数据的命名空间,它基于一个Cassandra相关的概念。

4. Cassandra Repository

我们将使用CassandraRepository作为数据访问层。这遵循Spring Data Repository抽象,它专注于抽象出跨不同持久性机制实现数据访问层所需的代码。

4.1 创建Cassandra Repository

让我们创建要在配置中使用的CassandraRepository:

@Repository
public interface BookRepository extends CassandraRepository<Book> {
    //
}

4.2 Cassandra Repository的配置

现在,我们可以扩展3.1节中的配置,在CassandraConfig中添加@EnableCassandraRepositories类级别注解来标记我们在4.1节中创建的CassandraRepository:

@Configuration
@EnableCassandraRepositories(
    basePackages = "cn.tuyucheng.taketoday.spring.data.cassandra.repository")
public classCassandraConfig extends AbstractCassandraConfiguration {
    //
}

5. 实体

让我们快速浏览一下实体-我们将要使用的模型类。该类被注解并定义了用于在嵌入式模式下创建元数据Cassandra数据表的附加参数。

使用@Table注解,bean直接映射到Cassandra数据表。每个属性也被定义为一种主键或一个简单的列:

@Table
public class Book {
    @PrimaryKeyColumn(
          name = "isbn",
          ordinal = 2,
          type = PrimaryKeyType.CLUSTERED,
          ordering = Ordering.DESCENDING)
    private UUID id;
    @PrimaryKeyColumn(
          name = "title", ordinal = 0, type = PrimaryKeyType.PARTITIONED)
    private String title;
    @PrimaryKeyColumn(
          name = "publisher", ordinal = 1, type = PrimaryKeyType.PARTITIONED)
    private String publisher;
    @Column
    private Set<String> tags = new HashSet<>();
    // standard getters and setters
}

6. 使用嵌入式服务器进行测试

6.1 Maven依赖项

如果你想在嵌入式模式下运行Cassandra(无需手动安装单独的Cassandra服务器),你需要在pom.xml中添加cassandra-unit相关依赖项:

<dependency>
    <groupId>org.cassandraunit</groupId>
    <artifactId>cassandra-unit-spring</artifactId>
    <version>2.1.9.2</version>
    <scope>test</scope>
    <exclusions>
        <exclusion>
        <groupId>org.cassandraunit</groupId>
        <artifactId>cassandra-unit</artifactId>
        </exclusion>
    </exclusions>
</dependency>
<dependency>
    <groupId>org.cassandraunit</groupId>
    <artifactId>cassandra-unit-shaded</artifactId>
    <version>2.1.9.2</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.hectorclient</groupId>
    <artifactId>hector-core</artifactId>
    <version>2.0-0</version>
</dependency>

可以使用嵌入式Cassandra服务器来测试此应用程序。主要优点是你不想显式安装Cassandra。

该嵌入式服务器也与Spring JUnit测试兼容。在这里,我们可以使用@RunWith注解和嵌入式服务器一起设置SpringJUnit4ClassRunner 。因此,无需运行外部Cassandra服务即可实现完整的测试套件。

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes =CassandraConfig.class)
public class BookRepositoryIntegrationTest {
    //
}

6.2 启动和停止服务器

如果你运行的是外部Cassandra服务器,则可以忽略此部分。

我们必须为整个测试套件启动一次服务器,因此服务器启动方法用@BeforeClass注解标记:

@BeforeClass
public static void startCassandraEmbedded() { 
    EmbeddedCassandraServerHelper.startEmbeddedCassandra(); 
    Cluster cluster = Cluster.builder()
        .addContactPoints("127.0.0.1").withPort(9142).build();
    Session session = cluster.connect(); 
}

接下来我们必须确保服务器在测试套件执行完成后停止:

@AfterClass
public static void stopCassandraEmbedded() {
    EmbeddedCassandraServerHelper.cleanEmbeddedCassandra();
}

6.3 清理数据表

最好在每次测试执行之前删除并创建数据表,以避免由于早期测试执行中的数据操作而导致意外结果。

现在我们可以在服务器启动时创建数据表:

@Before
public void createTable() {
    adminTemplate.createTable(
        true, CqlIdentifier.cqlId(DATA_TABLE_NAME), 
        Book.class, new HashMap<String, Object>());
}

并在每次执行单个测试用例后删除:

@After
public void dropTable() {
    adminTemplate.dropTable(CqlIdentifier.cqlId(DATA_TABLE_NAME));
}

7. 使用CassandraRepository访问数据

我们可以直接使用上面创建的BookRepository来持久化、操作和获取Cassandra数据库中的数据。

7.1 保存一本新书

我们可以将一本新书保存到我们的书店:

Book javaBook = new Book(
    UUIDs.timeBased(), "Head First Java", "O'Reilly Media", 
    ImmutableSet.of("Computer", "Software"));
bookRepository.save(ImmutableSet.of(javaBook));

然后我们可以检查数据库中插入的书的可用性:

Iterable<Book> books = bookRepository.findByTitleAndPublisher("Head First Java", "O'Reilly Media");
assertEquals(javaBook.getId(), books.iterator().next().getId());

7.2 更新现有书籍

让我们首先插入一本新书:

Book javaBook = new Book(
    UUIDs.timeBased(), "Head First Java", "O'Reilly Media", 
    ImmutableSet.of("Computer", "Software"));
bookRepository.save(ImmutableSet.of(javaBook));

让我们按书名取书:

Iterable<Book> books = bookRepository.findByTitleAndPublisher("Head First Java", "O'Reilly Media");

那我们改一下书名:

javaBook.setTitle("Head FirstJavaSecond Edition");
bookRepository.save(ImmutableSet.of(javaBook));

最后让我们检查标题是否在数据库中更新:

Iterable<Book> books = bookRepository.findByTitleAndPublisher(
  "Head FirstJavaSecond Edition", "O'Reilly Media");
assertEquals(
  javaBook.getTitle(), updateBooks.iterator().next().getTitle());

7.3 删除现有书籍

插入一本新书:

Book javaBook = new Book(
    UUIDs.timeBased(), "Head First Java", "O'Reilly Media",
    ImmutableSet.of("Computer", "Software"));
bookRepository.save(ImmutableSet.of(javaBook));

然后删除新输入的书:

bookRepository.delete(javaBook);

现在我们可以检查删除:

Iterable<Book> books = bookRepository.findByTitleAndPublisher("Head First Java", "O'Reilly Media");
assertNotEquals(javaBook.getId(), books.iterator().next().getId());

这将导致从代码中抛出一个NoSuchElementException以确保该书已被删除。

7.4 查找所有书籍

先插入一本新书:

Book javaBook = new Book(
    UUIDs.timeBased(), "Head First Java", "O'Reilly Media", 
    ImmutableSet.of("Computer", "Software"));
Book dPatternBook = new Book(
    UUIDs.timeBased(), "Head Design Patterns","O'Reilly Media",
    ImmutableSet.of("Computer", "Software"));
bookRepository.save(ImmutableSet.of(javaBook));
bookRepository.save(ImmutableSet.of(dPatternBook));

查找所有书籍:

Iterable<Book> books = bookRepository.findAll();

然后我们可以检查数据库中可用书籍的数量:

int bookCount = 0;
for (Book book : books) bookCount++;
assertEquals(bookCount, 2);

8. 总结

我们使用最常见的方法使用Cassandra Repository数据访问机制,通过Spring Data对Cassandra进行了基本的实践介绍。

与往常一样,本教程的完整源代码可在GitHub上获得。

Show Disqus Comments

Post Directory

扫码关注公众号:Taketoday
发送 290992
即可立即永久解锁本站全部文章