blog

Spring Data R2DBC MySQLのレスポンシブ操作

1.はじめに r2dbc-mysql の使い方は、Manipulating MySQL Databases with R2DBC という記事で紹介しました。MySQLをプライマリとボトムの助けを借りて...

Feb 18, 2020 · 7 min. read
シェア

はじめに

r2dbc-mysql の使い方は、 で紹介しました。DatabaseClientを使ったMySQLの操作はあまりにも初歩的で低レベルなので、開発には向いていません。今日はSpring Data R2DBCを使ってSpring Data Store抽象化スタイルのR2DBCデータベース操作のデモを行います。

注意: 現在Spring Data R2DBCはまだ発展途上で、いくつかの公式リリースで反復されていますが、本番で使えるほどではありません。しかし、将来は有望であり、勉強して学ぶ価値があります。

Spring Data R2DBC

Spring Data R2DBCはR2DBCリアクティブリレーショナルデータベースドライバに基づいて、一般的なリポジトリの抽象化を提供します。しかし、これはORMフレームワークではなく、データベースアクセスやR2DBCクライアントプログラムの抽象化レイヤと考えることができます。これは、ORMフレームワークは、キャッシュ、遅延ローディングや他の多くの機能を提供していませんが、それは、軽量で使いやすいと、データベースとオブジェクト間の抽象的なマッピング関係を抽象化します。

バージョン対応

Fattyは今日現在のSpring Data R2DBCとSpring Frameworkのバージョン対応をまとめました:

1.0.0.RELEASE 5.2.2.RELEASE
1.1.0.RELEASE 5.2.6.RELEASE
1.1.1.RELEASE 5.2.7.RELEASE
1.1.2.RELEASE 5.2.8.RELEASE

非互換を避けるために、必ずバージョン対応に注意してください。

Foundationの依存関係

R2DBCのコネクションプールを参照していませんでしたが、今回はそれを使ってみます。主な依存関係は以下の通りで、ここではSpring Webfluxも統合しています。

<dependency>
 <groupId>org.springframework.boot</groupId>
 <artifactId>spring-boot-starter-data-r2dbc</artifactId>
</dependency>
<!-- r2dbc コネクションプーリング>
<dependency>
 <groupId>io.r2dbc</groupId>
 <artifactId>r2dbc-pool</artifactId>
</dependency>
<!--r2dbc mysql  >
<dependency>
 <groupId>dev.miku</groupId>
 <artifactId>r2dbc-mysql</artifactId>
</dependency>
<!--自動設定のために導入する必要がある埋め込みデータベース型オブジェクト>
<dependency>
 <groupId>org.springframework.boot</groupId>
 <artifactId>spring-boot-starter-data-jdbc</artifactId>
</dependency>
<!-- リアクティブ・ウェブ・フレームワーク>
<dependency>
 <groupId>org.springframework.boot</groupId>
 <artifactId>spring-boot-starter-webflux</artifactId>
</dependency>

ここでは SpringBoot 2.3.2.RELEASEを使っています。

コンフィギュレーション

spring:
 r2dbc:
 url: r2dbcs:mysql://.1:3306/r2dbc
 username: root
 password: 123456

上記は、R2DBCの主な構成です。特別な注意がspring.r2dbc.urlの形式に支払われ、データベースに応じて異なる書かれている、ドライバの定義に応じて、これは非常に重要です。接続プーリングは、ここでデフォルトの構成を使用することができます、明示的に定義する必要はありません。

ビジネスコードを書く

次のステップはビジネスコードを書くことです。ここでもDatabaseClientを使ってclient_userテーブルを作成するDDL文を実行してみましたが、なかなかいい感じでした。

@Autowired
DatabaseClient databaseClient;
@Test
void doDDL() {
 List<String> ddl = Collections.unmodifiableList(Arrays.asList("drop table if exists client_user;", "create table client_user(user_id varchar(64) not null primary key,nick_name varchar(32),phone_number varchar(16),gender tinyint default 0) charset = utf8mb4;"));
 ddl.forEach(sql -> databaseClient.execute(sql)
 .fetch()
 .rowsUpdated()
 .as(StepVerifier::create)
 .expectNextCount(1)
 .verifyComplete());
}

データベースエンティティの宣言

Spring Data JPAに慣れ親しんでいる学生であれば、非常によく理解しているはずです。

/**
 * the client user type
 *
 * 
 */
@Data
@Table
public class ClientUser implements Serializable {
 private static final long serialVersionUID = -558043294043707772L;
 @Id
 private String userId;
 private String nickName;
 private String phoneNumber;
 private Integer gender;
}

CRUDインターフェースの宣言

ReactiveCrudRepository<T, ID>ReactiveSortingRepository<T, ID>上記のエンティティ・クラスの@Tableアノテーションは、継承する操作インタフェースが.

public interface ReactiveClientUserSortingRepository extends ReactiveSortingRepository<ClientUser,String> {
 
}

R2dbcRepository<T, ID>もちろん、@Table アノテーションが付けられていない場合は、エンティティ・クラスもインタフェースを継承できます。ReactiveClientUserSortingRepositoryそして、データベースを操作するためのメソッドを提供します。

次にSpring Data JPAの書き方ですが、こちらもほぼ書き方は同じですが、上記のページングや主キーポリシーなど、まだサポートされていない機能もあります。

PagingAndSortingRepository<T,ID>同様のリアクティブページング機能のインターフェイスは、現在稼働しておらず、将来のリリースで統合される予定です。

実用的

次のステップは、R2DBCを通して実際にMySQLデータベースを操作することです。以下の追加ロジックは、従来のロジックに従って書きました:

ClientUser clientUser = new ClientUser();
clientUser.setGender(2);
clientUser.setNickName("r2dbc");
clientUser.setPhoneNumber("9527");
clientUser.setUserId("snowflake");
Mono<ClientUser> save = reactiveClientUserSortingRepository.save(clientUser);

その結果、データはデータベースに書き込まれません。これは、r2jdbc-mysqlを直接使用することができず、実装してクライアントに委譲することしかできないためです。

これはR2DBCの設計原理でもあり、データベース間の差分部分をなくし、データベース全体を完全にリアクティブでバックプレッシャーにすることを目標に、SPIプレーンを最小化することを目指しています。主にクライアント・ライブラリ用のドライバSPIとして使用され、アプリケーション・コードで直接使用することは意図されていません。

そこで、reactor-testテストライブラリの助けを借りて、次のように書き換えて実行します:

reactiveClientUserSortingRepository.save(clientUser)
 .log()
 .as(StepVerifier::create)
 .expectNextCount(1)
 .verifyComplete();

update table [client_user]. Row with Id [snowflake] does not exist しかし、まだ正常に実行することはできません、プロンプトは、データベースが雪片レコードの主キーを見つけることができないため、新しいが、実際には更新を実行すると予想される、と言うことですエラーが報告されました。なぜそれは更新ですか?

これは、新しいのエンティティクラスは、プライマリキーが満たされているかどうかを決定するため、満たされていない場合は、新しいデータとみなされ、実際の新しい操作を取るには、プライマリキーが自動的にデータベースによって満たされる必要があります。太っちょは、Spring DataのR2DBCプロジェクトチームと通信し、友好的な解決策を得ませんでしたが、私は最初にここに穴を残す方法を見つけました。

では、どうやって新しいデータを追加するのでしょうか?SQLを記述するには、@Queryアノテーションを使用します:

@Modifying
@Query("insert into client_user (user_id,nick_name,phone_number,gender) values (:userId,:nickName,:phoneNumber,:gender)")
Mono<Integer> addClientUser(String userId, String nickName, String phoneNumber, Integer gender);

Mono<ClientUser>Modifyingを付けると、返り値は、モノ、モノ、モノのいずれかになります。

reactiveClientUserSortingRepository
 .addClientUser("snowflake",
 "r2dbc",
 "132****155",
 0)
 .as(StepVerifier::create)
 .expectNextCount(1)
 .verifyComplete();

これは、正常にデータが書き込まれたことを証明するものです。

Webfluxとの併用

しかし、実際にはどのように適用するのでしょうか?現在考えられるのは、Spring Data JPAとSpring MVCのように、リアクティブフレームワークSpring Webfluxの組み合わせです。

Webfluxのインターフェースを書いてください。

@RestController
@RequestMapping("/user")
public class ReactiveClientUserController {
 @Autowired
 private ReactiveClientUserSortingRepository reactiveClientUserSortingRepository;
 /**
 * ここでは、デフォルトのapiがレイヤー化されないことをテストする。
 *
 * @param userId the user id
 * @return the mono
 */
 @GetMapping("/{userId}")
 public Mono<ClientUser> findUserById(@PathVariable String userId) {
 return reactiveClientUserSortingRepository.findById(userId);
 }
}

並行性が低い場合は、Spring MVC + JDBCが最も良いパフォーマンスを示しますが、並行性が高い場合は、WebFlux + R2DBCがリクエスト処理あたりのリソース使用量が最も少なくなります。

高い同時実行数では、Spring MVC + JDBCの応答時間は低下し始めます。また、Spring WebFluxはSpring MVCを使った同様の実装よりも優れています。

Read next

Springファミリーの課題

IOCは、制御の反転は、コンテナへのオブジェクトの作成を達成するため、コンテナを作成する必要があり、それはオブジェクトの作成との間の関係を知っている必要があるので、Springのオブジェクトとその依存関係の管理は、IOCコンテナを介して達成される依存性の注入と依存関係のルックアップのIOC実装は、コンテナとAPIを介して依存関係のルックアップを積極的に探して、など。...

Feb 17, 2020 · 11 min read