これのつづき。
## 1.0.0.M6
数日前に1.0.0.M6が出たので、この前はM5のソースを読んでたけど今日はM6のにする。
Happy to announce @R2DBC 1.0 Milestone 6. @h2database and @SQLServer drivers are available now. https://t.co/J5c3RFvNdr
— Mark Paluch 👨💻&🎹 (@mp911de) November 20, 2018
## r2dbc-clientを見てみる
https://github.com/r2dbc/r2dbc-client/tree/master/src/main/java/io/r2dbc/client
r2dbc-clientはr2dbc-spiを人が使いやすいようにしてくれるためのシンプルなライブラリー。とりあえずは、この2つのクラスを見ておけば良さそうかな?
Handle
R2dbc
## Handle
Connection
のラッパー。結果をPublisher
じゃなくてMono
とかFlux
で返してくれたり、ちょこちょこ便利にしてくれてるっぽい。
## R2dbc
このクラスがr2dbc-clientを使うときの中心になる。コネクションファクトリーを渡してインスタンスを生成。
R2dbc r2dbc = new R2dbc(new PostgresqlConnectionFactory(configuration));
使うかなーと思うのは次の4つ。
withHandle
:ハンドルを使って処理をする。結果を返すやつ用。useHandle
:ハンドルを使って処理をする。結果を返さないやつ用。inTransaction
:トランザクション内で処理をする。結果を返すやつ用。useTransaction
:トランザクション内で処理をする。結果を返さないやつ用。
どれも、流れ的には
- コネクションをファクトリーから生成してハンドルを開く
- 処理をする
- ハンドルを閉じる
な感じ。エラーハンドリングもしてる。
### withHandle
というか、どれも最終的にはwithHandle
を使ってて、そこに上記の処理が書いてある感じ。
public <T> Flux<T> withHandle(Function<Handle, ? extends Publisher<? extends T>> f) { Objects.requireNonNull(f, "f must not be null"); return open() .flatMapMany(handle -> Flux.from( f.apply(handle)) .concatWith(ReactiveUtils.typeSafe(handle::close)) .onErrorResume(ReactiveUtils.appendError(handle::close))); }
へー。エラー処理はonErrorResume
ってのを使うんだねー。
### useHandle
へー。then()
でMono<Void>
を返すようにするのかー。
public Mono<Void> useHandle(Function<Handle, ? extends Publisher<?>> f) { Objects.requireNonNull(f, "f must not be null"); return withHandle(f) .then(); }
### inTransaction
「トランザクション内で処理をする」っていうハンドルのメソッドを呼び出してるだけ。
public <T> Flux<T> inTransaction(Function<Handle, ? extends Publisher<? extends T>> f) { Objects.requireNonNull(f, "f must not be null"); return withHandle(handle -> handle.inTransaction(f)); }
### useTransaction
それのuseHandle
版。
public Mono<Void> useTransaction(Function<Handle, ? extends Publisher<?>> f) { Objects.requireNonNull(f, "f must not be null"); return useHandle(handle -> handle.useTransaction(f)); }
## ということで
Handle
を引数にして処理をする関数を書けば良いみたいね。前回書いたこのコードは
private Flux<String> sample() { var connectionFactory = getPostgresqlConnectionFactory(); return connectionFactory.create() .flatMapMany(connection -> connection.createStatement("SELECT city FROM weather") .execute() .flatMap(result -> result.map((row, metadata) -> row.get("city", String.class) ) ) ); }
R2dbc
クラスを使うと、こんな感じで書ける。この例だとあんまり変わらないけど、トランザクションとか使ってるともっと違うんかな。
private Flux<String> sampleR2dbc() { var connectionFactory = getPostgresqlConnectionFactory(); var r2dbc = new R2dbc(connectionFactory); return r2dbc.withHandle(h -> h.createQuery("SELECT city FROM weather").mapRow( (row, metadata) -> row.get("city", String.class) )); }
面白いなー。