Saving Date Values in Spring Data Cassandra – 在Spring Data Cassandra中保存日期值

最后修改: 2021年 10月 21日

中文/混合/英文(键盘快捷键:t)

1. Overview

1.概述

Apache Cassandra is a scalable NoSQL database. It provides continuous availability with no single point of failure. In addition, Cassandra is able to handle large amounts of data with exceptional performance.

Apache Cassandra是一个可扩展的NoSQL数据库。它提供连续的可用性,没有单点故障。此外,Cassandra能够以卓越的性能处理大量的数据。

In this tutorial, we’ll look at connecting to Cassandra using Spring Data and Docker. Moreover, we’ll make use of the Spring Data repository abstraction to work with Cassandra’s data layer.

在本教程中,我们将研究如何使用Spring Data和Docker连接到Cassandra。此外,我们将利用Spring Data存储库的抽象,与Cassandra的数据层一起工作。

We’ll see how to save different Java date values in Cassandra. Finally, we’ll investigate how those date values are mapped to Cassandra types.

我们将看到如何在Cassandra中保存不同的Java日期值。最后,我们将研究这些日期值如何被映射到Cassandra类型。

2. Spring Data for Cassandra

2.卡桑德拉的Spring数据

Spring Data for Apache Cassandra offers Spring developers a familiar interface for working with Cassandra. This project applies core Spring concepts to the development of solutions using Cassandra data storage.

Spring Data for Apache Cassandra为Spring开发人员提供了熟悉的界面来处理Cassandra。该项目将 Spring 的核心概念应用于使用 Cassandra 数据存储的解决方案的开发。

Spring Data lets us create repositories based on common Spring interfaces. It also allows the use of QueryBuilders to eliminate the need to learn Cassandra Query Language (CQL). The project provides simple annotations that enable rich object mapping.

Spring Data让我们可以基于常见的Spring接口创建存储库。它还允许使用QueryBuilders来消除学习Cassandra查询语言(CQL)的需要。该项目提供了简单的注释,可以实现丰富的对象映射。

There are two important helper classes:

有两个重要的帮手类。

  • CqlTemplate handles common data access operations
  • CassandraTemplate provides object mapping

The project has noticeable similarities with Spring’s core JDBC support.

该项目与Spring的核心JDBC支持有明显的相似之处。

3. Setting Up a Test Environment

3.建立一个测试环境

In order to get started, we’ll need to set up a connection to a Cassandra instance.

为了开始工作,我们需要建立一个与Cassandra实例的连接。

Note that we can also connect to an Astra DB database instead, which is a cloud-based database built on Apache Cassandra.

注意,我们也可以连接到Astra DB数据库,这是一个基于Apache Cassandra的云数据库。

This guide will show you how to connect to a Datastax Astra DB.

本指南将告诉你如何连接到Datastax Astra DB.

3.1. Cassandra Container

3.1 Cassandra容器

Let’s configure and start Cassandra using the Testcontainers library. To begin with, we’ll define a Cassandra container and expose it to a specific port:

让我们使用Testcontainers库来配置和启动Cassandra。首先,我们将定义一个Cassandra容器,并将其暴露在一个特定的端口。

@Container
public static final CassandraContainer cassandra = (CassandraContainer) new CassandraContainer("cassandra:3.11.2")
    .withExposedPorts(9042);

Next, we’ll need to override test properties required for Spring Data to be able to establish a connection with the Cassandra container:

接下来,我们需要覆盖Spring Data所需的测试属性,以便能够与Cassandra容器建立连接。

TestPropertyValues.of(
    "spring.data.cassandra.keyspace-name=" + KEYSPACE_NAME,
    "spring.data.cassandra.contact-points=" + cassandra.getContainerIpAddress(),
    "spring.data.cassandra.port=" + cassandra.getMappedPort(9042)
).applyTo(configurableApplicationContext.getEnvironment());

Finally, before creating any objects/tables, we’ll need to create a keyspace:

最后,在创建任何对象/表之前,我们需要创建一个钥匙空间。

session.execute("CREATE KEYSPACE IF NOT EXISTS " + KEYSPACE_NAME + " WITH replication = {'class':'SimpleStrategy','replication_factor':'1'};");

A keyspace is simply a data container in Cassandra. In fact, it is very similar to a database in an RDBMS.

密钥空间在Cassandra中只是一个数据容器。事实上,它与RDBMS中的数据库非常相似。

3.2. Cassandra Repository

3.2.卡桑德拉资源库

Spring Data’s repository support significantly eases implementing DAOs. Let’s start by creating a simple DAO.

Spring Data的存储库支持大大简化了DAO的实现。让我们从创建一个简单的DAO开始。

The @Table annotation provided in the org.springframework.data.cassandra.core.mapping package enables domain object mapping:

@Table注解在org.springframework.data.cassandra.core.mapping包中提供,可以实现域对象映射。

@Table
public class Person {

    @PrimaryKey
    private UUID id;
    private String firstName;
    private String lastName;

    public Person(UUID id, String firstName, String lastName) {
        this.id = id;
        this.firstName = firstName;
        this.lastName = lastName;
    }

    //getters, setters, equals and hash code

}

Next, we’ll define a Spring Data repository for our DAO by extending the CassandraRepository interface:

接下来,我们将通过扩展CassandraRepository接口为我们的DAO定义一个Spring Data存储库。

@Repository
public interface PersonRepository extends CassandraRepository<Person, UUID> {}

Finally, we’ll need to define two additional properties before we can start writing integration tests:

最后,在我们开始编写集成测试之前,我们需要定义另外两个属性。

spring.data.cassandra.schema-action=create_if_not_exists
spring.data.cassandra.local-datacenter=datacenter1

The first property will ensure that Spring Data automatically creates the annotated tables for us.

第一个属性将确保Spring Data自动为我们创建注解的表。

We should note that this setting is not recommended for production systems.

我们应该注意,这种设置不建议用于生产系统

4. Using Date Values

4.使用日期值

In modern versions of Spring Data for Apache Cassandra, working with date values is quite straightforward. Spring Data will automatically ensure that Java date types are correctly mapped to and from an Apache Cassandra representation.

在现代版本的Apache Cassandra的Spring Data中,处理日期值是非常直接的。Spring Data将自动确保Java日期类型正确地映射到Apache Cassandra表示法,并从Apache Cassandra表示法中获得。

4.1. LocalDate Type

4.1.本地日期类型

Let’s add a new field birthDate of type LocalDate to our Person DAO:

让我们在我们的Person DAO中添加一个类型为LocalDate的新字段birthDate

@Test
public void givenValidPersonUsingLocalDate_whenSavingIt_thenDataIsPersisted() {
    UUID personId = UUIDs.timeBased();
    Person newPerson = new Person(personId, "Luka", "Modric");
    newPerson.setBirthDate(LocalDate.of(1985, 9, 9));
    personRepository.save(newPerson);

    List<Person> savedPersons = personRepository.findAllById(List.of(personId));
    assertThat(savedPersons.get(0)).isEqualTo(newPerson);
}

Spring Data automatically converts Java’s LocalDate to Cassandra’s date type. The LocalDate value in the DAO is identical after saving and fetching the record from Cassandra.

Spring Data自动将Java的LocalDate转换为Cassandra的date类型。在保存和从Cassandra获取记录后,DAO中的LocalDate值是相同的。

4.2. LocalDateTime Type

4.2.LocalDateTime类型

Let’s add another field called lastVisitedDate of type LocalDateTime to our Person DAO:

让我们为我们的Person DAO添加另一个类型为LocalDateTime的名为lastVisitedDate的字段。

@Test
public void givenValidPersonUsingLocalDateTime_whenSavingIt_thenDataIsPersisted() {
    UUID personId = UUIDs.timeBased();
    Person newPerson = new Person(personId, "Luka", "Modric");
    newPerson.setLastVisitedDate(LocalDateTime.of(2021, 7, 13, 11, 30));
    personRepository.save(newPerson);

    List<Person> savedPersons = personRepository.findAllById(List.of(personId));
    assertThat(savedPersons.get(0)).isEqualTo(newPerson);
}

Spring Data automatically converts Java’s LocalDateTime to Cassandra’s timestamp type. The LocalDateTime value in the DAO is identical after saving and fetching the record from Cassandra.

Spring Data自动将Java的LocalDateTime转换为Cassandra的timestamp类型。在保存和从Cassandra获取记录后,DAO中的LocalDateTime值是相同的。

4.3. Legacy Date Type

4.3.遗留日期类型

Finally, let’s add a field called lastPurchasedDate of the legacy type Date to our Person DAO:

最后,让我们为我们的Person DAO添加一个名为lastPurchasedDate的字段,该字段属于传统类型Date

@Test
public void givenValidPersonUsingLegacyDate_whenSavingIt_thenDataIsPersisted() {
    UUID personId = UUIDs.timeBased();
    Person newPerson = new Person(personId, "Luka", "Modric");
    newPerson.setLastPurchasedDate(new Date(LocalDate.of(2021, 7, 13).toEpochDay()));
    personRepository.save(newPerson);

    List<Person> savedPersons = personRepository.findAllById(List.of(personId));
    assertThat(savedPersons.get(0)).isEqualTo(newPerson);
}

As with LocalDateTime, Spring Data converts Java’s java.util.Date to Cassandra’s timestamp type.

LocalDateTime一样,Spring Data将Java的java.util.Date转换为Cassandra的timestamp类型

4.4. Mapped Cassandra Types

4.4.映射的Cassandra类型

Let’s check the data that was saved in Cassandra by using CQLSH. It’s a command-line shell for interacting with Cassandra through CQL.

让我们通过使用CQLSH来检查保存在Cassandra中的数据。这是一个通过CQL与Cassandra互动的命令行shell

In order to check what data has been stored in the Cassandra container during test execution, we can simply put a breakpoint in our test. During the paused test execution, we can then connect to the Docker container CLI via the Docker Desktop application:

为了在测试执行期间检查Cassandra容器中存储了哪些数据,我们可以简单地在测试中设置一个断点。在暂停的测试执行期间,我们可以通过Docker桌面应用程序连接到Docker容器CLI。

After connecting to the Docker container CLI, we should first select the keyspace and then the table:

连接到Docker容器CLI后,我们应该首先选择密钥空间,然后选择表。

# cqlsh
Connected to Test Cluster at 127.0.0.1:9042.
[cqlsh 5.0.1 | Cassandra 3.11.2 | CQL spec 3.4.4 | Native protocol v4]
Use HELP for help.
cqlsh> USE test;
cqlsh:test> select * from person;

As a result, CQLSH will display us a formatted output of the data saved in the table:

结果,CQLSH将向我们显示保存在表中的数据的格式化输出。

 id                                   | birthdate  | firstname | lastname | lastpurchaseddate | lastvisiteddate
--------------------------------------+------------+-----------+----------+-------------------+-----------------
 9abef910-e3fd-11eb-9829-c5149ac796de | 1985-09-09 |      Luka |   Modric |              null |            null

However, we would also like to check the data types used for the specific date columns:

然而,我们也想检查特定日期列所使用的数据类型。

cqlsh:test> DESC TABLE person;

The output returns a CQL command used to create the table. Therefore, it contains all data types definitions:

输出返回一个用于创建表的CQL命令。因此,它包含所有数据类型的定义。

CREATE TABLE test.person (
    id uuid PRIMARY KEY,
    birthdate date,
    firstname text,
    lastname text,
    lastpurchaseddate timestamp,
    lastvisiteddate timestamp
)

5. Conclusion

5.总结

In this article, we explored working with different date values in Spring Data for Apache Cassandra.

在这篇文章中,我们探讨了在Spring Data for Apache Cassandra中处理不同的日期值。

In the examples, we covered working with LocalDate, LocalDateTime, and the legacy Date Java type. We saw how to connect to a Cassandra instance started using Testcontainers. Finally, we used the Spring Data repository abstraction to manipulate with data stored in Cassandra.

在这些例子中,我们涵盖了与LocalDateLocalDateTime和传统的Date Java类型的工作。我们看到如何使用Testcontainers开始连接到Cassandra实例。最后,我们使用Spring Data资源库抽象来操作存储在Cassandra中的数据。

As always, the source code is available over on GitHub.

像往常一样,源代码可在GitHub上获得