Slide 1

Slide 1 text

R2DBCをサポートするORM Komapper 2022/04/15 Server-Side Kotlin Meetup vol.2

Slide 2

Slide 2 text

はじめに|⾃⼰紹介 nakamura-to nakamura_to 電通国際情報サービス(ISID)ソフトウェアデザインセンター • テックブログやっています︓https://tech.isid.co.jp/ • 所属部署のMeetyあります︓https://meety.net/matches/nIQGCTRTozzF OSSライブラリ開発者 • 代表プロダクト︓Doma https://github.com/domaframework/doma Font Awesome Icons under CC-BY 4.0 https://fontawesome.com/

Slide 3

Slide 3 text

Komapperとは Kotlinで作られたKotlinのためのORMライブラリ • 個⼈で開発しているOSS(2021/03〜) • JDBCとR2DBCに対応 https://github.com/komapper

Slide 4

Slide 4 text

JDBCとは データベースアクセスのためのAPI データベース JDBC ドライバ ORMライブラリ アプリケーション JDBC API Komapper Exposed Hibernate JOOQ MyBatis 広義のORMライブラリ

Slide 5

Slide 5 text

R2DBCとは データベースアクセスのためのリアクティブなAPI • R2DBC = Reactive Relational Database Connectivity データベース R2DBC ドライバ ORMライブラリ アプリケーション R2DBC API ノンブロッキングIO Komapper Spring Data R2DBC JOOQ リアクティブなAPI 広義のORMライブラリ • 効率的 • スケールしやすい • ノンブロッキングIOと 相性が良い

Slide 6

Slide 6 text

R2DBCのリアクティブなAPIの利⽤例 ConnectionFactory connectionFactory = ConnectionFactories .get("r2dbc:h2:mem:///testdb"); Mono.from(connectionFactory.create()) .flatMapMany(connection -> connection .createStatement("SELECT firstname FROM PERSON WHERE age > $1") .bind("$1", 42) .execute()) .flatMap(result -> result .map((row, rowMetadata) -> row.get("firstname", String.class))) .doOnNext(System.out::println) .subscribe(); R2DBCサイトに掲載のサンプルコード(Javaコード) リアクティブなAPIは難しい

Slide 7

Slide 7 text

Komapperのコード例|JDBC接続とR2DBC接続で共通のコード @KomapperEntity data class Employee( @KomapperId @KomapperAutoIncrement val id: Int, val name: String ) create table employee ( id integer generated always as identity not null, name varchar(500) not null, constraint pk_employee primary key(id) ) 従業員テーブル 従業員クラス(Kotlinコード)

Slide 8

Slide 8 text

Komapperのコード例|JDBC接続の場合 // ①データベースインスタンスの作成 val db = JdbcDatabase(“jdbc:h2:mem:test;DB_CLOSE_DELAY=-1”) // ②名前で従業員⼀覧を取得するクエリの構築 val e = Meta.employee val query: Query> = QueryDsl.from(e).where { e.name eq "ABC" }.orderBy(e.id) fun main() { // ③クエリの実⾏ val employees : List = db.runQuery(query) } select t0_.id, t0_.name from employee as t0_ where t0_.name = ? order by t0_.id asc Kotlinコード 発⾏されるSQL

Slide 9

Slide 9 text

Komapperのコード例|R2DBC接続の場合 // ①データベースインスタンスの作成 val db = R2dbcDatabase(“r2dbc:h2:mem:///test;DB_CLOSE_DELAY=-1”) // ②名前で従業員⼀覧を取得するクエリの構築 val e = Meta.employee val query: Query> = QueryDsl.from(e).where { e.name eq "ABC" }.orderBy(e.id) suspend fun main() { // ③クエリの実⾏ val employees : List = db.runQuery(query) } select t0_.id, t0_.name from employee as t0_ where t0_.name = ? order by t0_.id asc Kotlinコード 発⾏されるSQL

Slide 10

Slide 10 text

Komapperのコード例|JDBC接続とR2DBC接続の⽐較 違いはごくわずか • データベースのインスタンスが違う • R2DBC接続ではrunQueryをsuspend関数内で呼び出す val db = JdbcDatabase(“jdbc:h2:mem:test;DB_CLOSE_DELAY=-1”) val e = Meta.employee val query = QueryDsl.from(e).where { e.name eq "ABC" }.orderBy(e.id) fun main() { val employees = db.runQuery(query) } val db = R2dbcDatabase(“r2dbc:h2:mem:///test;DB_CLOSE_DELAY=-1”) val e = Meta.employee val query = QueryDsl.from(e).where { e.name eq "ABC" }.orderBy(e.id) suspend fun main() { val employees = db.runQuery(query) } JDBC接続 R2DBC接続 接続⽂字列は⽐較対象にしていません

Slide 11

Slide 11 text

Komapperの特徴のまとめ|その1 JDBC版とR2DBC版のAPIがほとんど同じ • コードやノウハウを再利⽤できる

Slide 12

Slide 12 text

Komapperの特徴のまとめ|その2 R2DBC版にはリアクティブ特有の処理が出てこない • リアクティブな処理をコルーチンに変換している • リアクティブなAPIの難しさを低減させている ConnectionFactory connectionFactory = ConnectionFactories .get("r2dbc:h2:mem:///testdb"); Mono.from(connectionFactory.create()) .flatMapMany(connection -> connection .createStatement("SELECT firstname FROM PERSON WHERE age > $1") .bind("$1", 42) .execute()) .flatMap(result -> result .map((row, rowMetadata) -> row.get("firstname", String.class))) .doOnNext(System.out::println) .subscribe(); 再掲のJavaコード。Komapperでは⻘字のようなリアクティブ特有の処理が不要

Slide 13

Slide 13 text

主要フレームワークとの連携 Komapperは主要なフレームワークをサポート • Spring Framework • Ktor

Slide 14

Slide 14 text

主要フレームワークとの連携|Spring Framework JDBCとR2DBCのどちらもサポート • JDBC版はWeb MVC、R2DBC版はWebFluxと組みわせるのがオススメ @RestController @Transactional class MyController(private val db: JdbcDatabase) { @RequestMapping("/") fun list(): List { val e = Meta.employee val query = QueryDsl.from(e).orderBy(e.id) return db.runQuery(query) } } Komapper JDBC + Spring Web MVC @RestController @Transactional class MyController(private val db: R2dbcDatabase) { @RequestMapping("/") suspend fun list(): List { val e = Meta.employee val query = QueryDsl.from(e).orderBy(e.id) return db.runQuery(query) } } Komapper R2DBC + Spring WebFlux

Slide 15

Slide 15 text

主要フレームワークとの連携|Ktor R2DBCをサポート • Ktorの⾮同期プログラミングモデルと相性が良い val db = R2dbcDatabase("r2dbc:h2:mem:///example;DB_CLOSE_DELAY=-1") fun Application.configureRouting() { routing { get("/") { val e = Meta.employee val query = QueryDsl.from(e).orderBy(e.id) db.withTransaction { val employees = db.runQuery(query) call.respond(employees) } } } } Komapper R2DBC + Ktor 2.0

Slide 16

Slide 16 text

JDBCとR2DBCどちらを使うべきか 効率性やスケーラビリティ重視ならR2DBCだが… • 堅実性重視ならJDBC。 JDBCには⻑い実績があり情報も豊富。 • R2DBCはこれからの技術。トラブル時、問題の切り分けに苦労するリスクあり。

Slide 17

Slide 17 text

Komapperの特徴のまとめ|再掲 JDBC版とR2DBC版のAPIがほとんど同じ • コードやノウハウを再利⽤できる

Slide 18

Slide 18 text

Komapperのこれから 現時点でv0.32.0が最新 R2DBC 0.9.1を利⽤ 5⽉上旬 v1.0-betaリリース R2DBC 1.0に対応 5⽉下旬 v1.0リリース R2DBCドライバの対応状況次第では遅れる可能性があります v1.0を5⽉にリリース予定

Slide 19

Slide 19 text

参考情報 Komapper • https://www.komapper.org/ • Webサイト • https://github.com/komapper/komapper-examples • Spring Boot、Ktor、Quarkusのサンプルアプリ R2DBC • https://r2dbc.io/ • Webサイト • https://r2dbc.io/spec/0.9.1.RELEASE/spec/html/ • R2DBCの仕様