在 Spring Data Cassandra 中保存日期值

1. 概述

Apache Cassandra 是一個可擴展的 NoSQL 數據庫。它提供了無單點故障的持續可用性。此外,Cassandra 能夠以卓越的性能處理大量數據。

在本教程中,我們將了解使用 Spring Data 和 Docker 連接到 Cassandra。此外,我們將利用 Spring Data 存儲庫抽象來處理 Cassandra 的數據層。

我們將看到如何在 Cassandra 中保存不同的 Java 日期值。最後,我們將研究這些日期值如何映射到 Cassandra 類型。

2. Cassandra 的 Spring 數據

Spring Data for Apache Cassandra 為 Spring 開發人員提供了一個熟悉的界面來使用 Cassandra 。該項目將核心 Spring 概念應用於使用 Cassandra 數據存儲的解決方案的開發。

Spring Data 允許我們基於常見的 Spring 接口創建存儲庫。它還允許使用QueryBuilders來消除學習 Cassandra 查詢語言 (CQL) 的需要。該項目提供了支持豐富對象映射的簡單註釋。

有兩個重要的輔助類:

  • CqlTemplate處理常見的數據訪問操作
  • CassandraTemplate提供對象映射

該項目與 Spring 的核心 JDBC 支持有明顯的相似之處。

3. 搭建測試環境

為了開始,我們需要建立一個到 Cassandra 實例的連接。

請注意,我們也可以連接到 Astra DB 數據庫,這是一個基於 Apache Cassandra 的基於雲的數據庫。

本指南將向您展示如何連接到 Datastax Astra DB

3.1.卡桑德拉容器

Testcontainers庫來配置和啟動 Cassandra。首先,我們將定義一個 Cassandra 容器並將其暴露在特定端口上:

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

接下來,我們需要覆蓋 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());

最後,在創建任何對象/表之前,我們需要創建一個鍵空間:

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

密鑰空間只是 Cassandra 中的一個數據容器。實際上,它與 RDBMS 中的數據庫非常相似。

3.2. Cassandra 存儲庫

Spring Data 的存儲庫支持大大簡化了 DAO 的實現。讓我們從創建一個簡單的 DAO 開始。

org.springframework.data.cassandra.core.mapping包中提供的@Table註釋啟用域對象映射:

@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

 }

CassandraRepository接口為我們的 DAO 定義一個 Spring Data 存儲庫:

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

最後,在開始編寫集成測試之前,我們需要定義兩個額外的屬性:

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

第一個屬性將確保 Spring Data 自動為我們創建帶註釋的表。

我們應該注意,不建議將此設置用於生產系統

4. 使用日期值

在用於 Apache Cassandra 的 Spring Data 的現代版本中,處理日期值非常簡單。 Spring Data 將自動確保 Java 日期類型與 Apache Cassandra 表示正確映射。

4.1.本地日期類型

讓我們向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 自動將 Java 的LocalDate轉換為 Cassandra 的date類型。從 Cassandra 保存和獲取記錄後,DAO 中的LocalDate

4.2.本地日期時間類型

讓我們向Person DAO 添加另一個名為lastVisitedDate LocalDateTime類型的字段:

@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 自動將 Java 的LocalDateTime轉換為 Cassandra 的時間戳類型。從 Cassandra 保存和獲取記錄後,DAO 中的LocalDateTime

4.3.舊日期類型

最後,讓我們將遺留類型Date 的**名為 lastPurchasedDate的字段添加到我們的Person DAO 中:

@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);
 }

LocalDateTime, Spring Data 將 Java 的java.util.Date轉換為 Cassandra 的時間戳類型

4.4.映射的 Cassandra 類型

讓我們使用 CQLSH 檢查保存在 Cassandra 中的數據。它是一個命令行 shell,用於通過 CQL 與 Cassandra 進行交互。

為了在測試執行期間檢查 Cassandra 容器中存儲了哪些數據,我們可以簡單地在我們的測試中放置一個斷點。在暫停的測試執行期間,我們可以通過 Docker 桌面應用程序連接到 Docker 容器 CLI:

在

連接到 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;

因此,CQLSH 將向我們顯示保存在表中的數據的格式化輸出:

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

但是,我們還想檢查用於特定日期列的數據類型:

cqlsh:test> DESC TABLE person;

輸出返回用於創建表的 CQL 命令。因此,它包含所有數據類型定義:

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

5. 結論

在本文中,我們探討瞭如何在 Spring Data for Apache Cassandra 中使用不同的日期值。

在示例中,我們介紹瞭如何使用LocalDateLocalDateTime,和遺留的Date Java 類型。我們看到瞭如何連接到使用Testcontainers開始的 Cassandra 實例。最後,我們使用 Spring Data 存儲庫抽象來操作存儲在 Cassandra 中的數據。