使用Spring Boot和Scalar DB构建API的方法①

太长不看

我们使用由Scalar株式会社开发的分布式事务管理器Scalar DB来创建处理事务的API。

我打算解释一下我学到的Scalar DB的特点以及使用Scalar DB开发API的方法。

由于长度较长,我将分三次发布。

    • Spring BootとScalar DBを用いたAPIの作り方①(本記事)

 

    • Spring BootとScalar DBを用いたAPIの作り方②

 

    Spring BootとScalar DBを用いたAPIの作り方③

已经将完成的项目公开在 GitHub 上。

索引

    1. 为什么要在Spring Boot中使用Scalar DB

Scalar DB概述
使用Scalar DB的优势

Spring Boot中的API架构及每个层的角色

各层的角色
Scalar DB在每个层的实现
API架构

示例应用概述

要求
环境设置
目录结构

数据模型设计
端点设计

在Spring Boot中引入Scalar DB的方法

安装库
创建属性文件
创建模式文件
设置数据模式

使用Spring Boot的原因是使用Scalar DB。

Scalars DB 的概述

Scalar DB是一个事务管理器,它可以为不符合ACID标准的数据库提供符合ACID标准的事务处理能力。

Scalar DB通过存储抽象层和存储适配器对数据库进行抽象化,如下图所示。因此,使用Scalar DB的应用程序无需意识到所使用的数据库的差异,可以在同一程序中使用各种不同的数据库。

Scalar DB Architecture

在Scalar DB中,可以将多个不同的数据库作为一个数据库进行处理。因此,可以使用同一个程序对多个不同的数据库进行ACID事务处理。
目前支持的数据库有Cassandra、Cosmos DB、DynamoDB、MySQL和PostgreSQL。

支持的数据库

请参阅官方文件以获得详细说明。

使用Scalar DB的好处

我想在Spring Boot中,很常见的做法是使用@Transaction注解来实现事务处理。

使用Scalar DB来实现事务有以下好处:

    • データベースの種類にかかわらず、トランザクション分離レベルを Strict Serializable にできる

 

    • 異なるデータベース/ストレージでも同じコードで実装できる

 

    別々の、あるいは異なるデータベース間でも、同じインターフェイスで、同じ分離レベルで実装することができる。

无论数据库类型如何,都可以将事务隔离级别设置为严格可序列化。

如果使用@Transaction注解来实现事务处理,事务隔离级别将取决于所使用的数据库/存储系统。

一方,Scalar DB的事务隔离级别被设置为Read Committed Snapshot Isolation,并且可以设置最高为Strict Serializable的隔离级别。因此,即使是支持范围有限的数据库也可以进行适配。

在不同的数据库 / 存储系统中,可以使用相同的代码进行实现。

正如上述所述,Scalar DB将对数据库/存储的访问进行了抽象化,因此应用程序无需关注数据库/存储的类型。因此,只要Scalar DB支持的数据库/存储,就可以在同一程序中实现。

此外,您只需修改所述的配置文件,而无需更改任何代码,就能够更换数据库/存储系统。

可以在不同的数据库之间使用相同的界面和相同的隔离级别进行实现。

在@Transaction注解中,无法在不同的数据库/存储之间执行ACID事务。

一方,Scalar DB具有多存储介质的支持,可以在受到不同机型之间、数据库之间、分区之间和表之间事务约束的环境中,通过相同的界面,在最高严格可串行化隔离级别下进行实现。

※ 参考:
可序列化的字符串

在Spring Boot中的API架构和每个层的角色

每个层次的角色

Spring Boot采用分层架构,其中包含以下四个层,每个层与其下方或上方的层进行通信。

Spring Boot Layer

展示层

演示层由控制器类构成,负责处理HTTP请求,并将JSON参数转换为对象,然后将请求授权并转发到业务层。

商业层

业务层负责处理业务逻辑。它由服务类构成,处理来自表示层的数据,转发到持久层,并将结果返回给表示层。此外,还会处理认证和验证的任务。

持久层

持久层由Repository类构成,负责与数据库进行连接,并处理从业务层传递过来的数据的CRUD操作请求,并将结果返回给业务层。

数据库层

数据库层会对从持久化层传输的数据和请求执行CRUD操作。

在Scalar DB的每个层次上的实现。

Scalar DB会将在Persistence Layer中编写的操作作为一系列操作在Business Layer中执行,并将其作为事务一起执行。
– 在Persistence Layer中,使用Scalar DB的方法来编写对数据库表的CRUD操作。
– 在Business Layer中,使用Scalar DB的方法来编写事务处理。

API架构

基于以上考虑,Spring Boot中的API架构如下所示。

Spring_Boot_API_Architecture

DTO保存有从HTTP请求传输或返回数据的功能。Model保存用于永久存储到数据库的数据。在Mapper中将DTO和Model的数据进行映射,然后将数据传递给Controller类、Service类和Repository类。

示例应用程序的概述

用户会保存所属的群组信息,并且群组会保存属于该群组的用户信息。
因此,如果要更改用户所属的群组,需要同时更新用户和群组的信息。

一般而言,使用NoSQL数据库的实现通常不进行第三范式化,因此在用户和群组两方面都保留信息,并实现能够满足两者的查询需求。

用户具有管理员权限和普通权限,并根据所属的组分配权限以进行访问控制。

重要的事项

    • 全ユーザーは自身の情報を登録できる

 

    • 一般ユーザーは自分自身の情報の取得、更新、削除ができる

 

    • 管理者は全てのユーザー情報の取得、更新、削除ができる

 

    • 管理者および一般ユーザーはグループを作成できる。作成したユーザーは自動的にそのグループに所属する

 

    • 一般ユーザーは所属するグループに対して、メンバーの追加・脱退、メンバー一覧の取得、グループの削除ができる

 

    • 管理者は全てのグループに対してメンバーの追加・脱退、メンバー一覧の取得、グループの削除ができる

 

    一般ユーザーおよび管理者は全てのグループを一覧取得できる

环境建设

    • Spring Boot 2.5.6

 

    • Scalar DB 3.3.0

 

    • Java 8

 

    Cassandra 3.11

目录结构

.
├── api
|   ├── build.gradle
│   ├── src
│   │   ├── main
│   │   │   ├── java
│   │   │   │   └── com
│   │   │   │       └── example
│   │   │   │           └── api
│   │   │   │               ├── Application.java
│   │   │   │               ├── config
│   │   │   │               ├── controller
│   │   │   │               ├── dto
│   │   │   │               ├── exception
│   │   │   │               ├── model
│   │   │   │               ├── repository
│   │   │   │               ├── service
│   │   │   │               └── util
│   │   │   └── resources
│   │   │       └── database.properties
│   │   └── test
│   │       ├── java
│   │       │   └── com
│   │       │       └── example
│   │       │           └── api
│   │       │               ├── controller
│   │       │               ├── cucumber
│   │       │               ├── repository
│   │       │               ├── security
│   │       │               ├── service
│   │       └── resources
└── tools
│   ├── scalardb-schema-loader-3.3.0.jar
│     └── schema
│        └── schema.json
└── docker-compose.yml

数据模型的设计

我们创建的API数据模型如下。

data-model
    • ユーザーとグループ管理を NoSQLであるCassandra を用いて行うケースを想定しています。

 

    • Userテーブルには、どのグループに所属しているかという情報を保持し、Groupテーブルにはどのようなユーザーが所属しているのかという情報を保持しています。

 

    このため、どちらかのテーブルを更新する際には、双方に存在するレコードを同時に更新する必要があります。

终点的设计

我已经设计了以下的终端点。

URIHTTPメソッドDescription/usersPOSTユーザーを登録する/usersGETユーザーを一覧取得する/users/{user_id}GETユーザー情報を取得する/users/{user_id}PUTユーザー情報を更新する/users/{user_id}DELETEユーザーを削除する/groupsPOSTグループを登録する/groupsGETグループ一覧を取得する/groups/{group_id}/group-usersPUTグループにユーザーを追加する/groups/{group_id}/group-usersGETグループに所属するユーザーを一覧取得する/groups/{group_id}/group-users/{user_id}PUTグループからユーザーを脱退させる/groups/{group_id}DELETEグループを削除する

使用Spring Boot引入Scalar DB的方法

通过安装Scalar DB库,并创建属性文件和模式文件,再使用模式加载器将属性文件和模式文件加载到数据库中,可以创建命名空间和表。

安装图书馆

Scalar DB库可以在Maven Central上使用。请使用Gradle或Maven等构建工具进行安装。

dependencies {
    implementation group: 'com.scalar-labs', name: 'scalardb', version: '3.3.0'
}
<dependency>
  <groupId>com.scalar-labs</groupId>
  <artifactId>scalardb</artifactId>
  <version>3.3.0</version>
</dependency>

创建属性文件

为了连接数据库/存储,Scalar DB将创建一个属性文件。在本次设置中,我们将使用Cassandra作为本地环境。文件名将为database.properties。

Scalar DB支持的数据库

请参考各个数据库中的属性文件配置方法。

# Comma separated contact points
scalar.db.contact_points=localhost

# Port number for all the contact points. Default port number for each database is used if empty.
scalar.db.contact_port=9042

# Credential information to access the database
scalar.db.username=cassandra
scalar.db.password=cassandra

# Cassandra storage implementation
scalar.db.storage=cassandra

创建模式文件

模式文件将使用JSON文件创建。这次我们将其保存为schema.json。

{
  "demo.groups": {
    "transaction": true,
    "partition-key": [
      "group_id"
    ],
    "clustering-key": [],
    "columns": {
      "group_id": "TEXT",
      "group_name": "TEXT",
      "group_users": "TEXT",
      "common_key": "TEXT"
    },
    "secondary-index": [
      "common_key"]
  },
  "demo.users": {
    "transaction": true,
    "partition-key": [
      "user_id"
    ],
    "clustering-key": [],
    "columns": {
      "user_id": "TEXT",
      "email": "TEXT",
      "family_name": "TEXT",
      "given_name": "TEXT",
      "user_detail": "TEXT",
      "user_groups": "TEXT",
      "common_key": "TEXT"
    },
    "secondary-index": [
      "common_key"
    ]
  }
}

“但这部分将是Cassandra数据库的键空间。”

在”demo”之后的句号后面,”groups”和”users”将成为表名。

如果想要进行交易,请将transaction设为true。

请根据设计的数据模型,指定分区键(partition-key),聚簇键(clustering-key)并在列中记录键和数据类型。有关Scalar DB支持的数据类型,请参考Scalar DB中的数据库模式。

另外,为了获取所有表格数据,我们创建了一个辅助索引。
在卡桑德拉中,使用辅助索引是不推荐的,但是考虑到这次创建的API数据数量不多且更新频率不高的列,我们决定使用它。

设置数据架构

使用创建的属性文件和模式文件来设置数据库的数据模式。

请先确认Cassandra已经启动。
这次我们是在Docker上启动的。

version: '3.8'
services:
  cassandra:
    image: arm64v8/cassandra:3.11
    container_name: "cassandra-1"
    volumes:
      - ./docker/cassandra-data:/var/lib/cassandra
    ports:
      - "9042:9042"
$ docker-compose up -d

从 Scalar DB 的 GitHub 中下载与 ScalarDB 相同版本的模式加载器。

请根据目录结构参考各个文件的存放位置。

$ java -jar tools/scalardb-schema-loader-3.3.0.jar --config api/src/main/resources/database.properties --coordinator -f tools/schema/schema.json

以下是执行结果。

********************************
********************************
[main] INFO com.scalar.db.schemaloader.core.SchemaOperator - Creating the table groups in the namespace demo succeeded.
[main] INFO com.scalar.db.schemaloader.core.SchemaOperator - Creating the table users in the namespace demo succeeded.

我们已经创建了表。为了确认,让我们尝试使用CQL进行验证。

$ docker exec -it cassandra-1 cqlsh
cqlsh> DESC demo.users

CREATE TABLE demo.users (
    user_id text PRIMARY KEY,
    before_common_key text,
    before_email text,
    before_family_name text,
    before_given_name text,
    before_tx_committed_at bigint,
    before_tx_id text,
    before_tx_prepared_at bigint,
    before_tx_state int,
    before_tx_version int,
    before_user_detail text,
    before_user_groups text,
    common_key text,
    email text,
    family_name text,
    given_name text,
    tx_committed_at bigint,
    tx_id text,
    tx_prepared_at bigint,
    tx_state int,
    tx_version int,
    user_detail text,
    user_groups text
)

cqlsh> DESC demo.users

CREATE TABLE demo.groups (
    group_id text PRIMARY KEY,
    before_common_key text,
    before_group_name text,
    before_group_users text,
    before_tx_committed_at bigint,
    before_tx_id text,
    before_tx_prepared_at bigint,
    before_tx_state int,
    before_tx_version int,
    common_key text,
    group_name text,
    group_users text,
    tx_committed_at bigint,
    tx_id text,
    tx_prepared_at bigint,
    tx_state int,
    tx_version int
)

一切無問題,數據結構設置已經完成。

下次我们会详细说明具体的API实施方法。

使用Spring Boot和Scalar DB创建API的方法②

广告
将在 10 秒后关闭
bannerAds