Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
「2024年版 Kotlin サーバーサイドプログラミング実践開発」の補講 〜O/Rマッパー編〜
Search
Takehata Naoto
July 18, 2024
Programming
2
690
「2024年版 Kotlin サーバーサイドプログラミング実践開発」の補講 〜O/Rマッパー編〜
2024年7月18日(土) 「Server-side Kotlin Night 2024/07」の発表資料です。
Takehata Naoto
July 18, 2024
Tweet
Share
More Decks by Takehata Naoto
See All by Takehata Naoto
KotlinConf 2025で発表された言語のアップデートと現地参加レポート
n_takehata
1
28
KotlinConf 2025 現地で感じたServer-Side Kotlin
n_takehata
1
230
KotlinConf 2025 現地参加の土産話
n_takehata
0
110
組織貢献をするフリーランスエンジニアという生き方
n_takehata
2
3.7k
2024年版 Kotlin サーバーサイドプログラミング実践開発
n_takehata
7
5.9k
Server-Side目線で見る、Kotlin Festの楽しみ方
n_takehata
0
480
KotlinとCloud Vision APIで領収書の電子帳簿保存法対応をする
n_takehata
1
1.5k
KotlinConf 2023 現地参加レポート
n_takehata
1
360
サーバーサイドKotlinクイズ
n_takehata
0
220
Other Decks in Programming
See All in Programming
Elixir で IoT 開発、 Nerves なら簡単にできる!?
pojiro
1
150
レガシーシステムの機能調査・開発におけるAI利活用
takuya_ohtonari
0
610
既存デザインを変更せずにタップ領域を広げる方法
tahia910
1
240
来たるべき 8.0 に備えて React 19 新機能と React Router 固有機能の取捨選択とすり合わせを考える
oukayuka
2
840
Select API from Kotlin Coroutine
jmatsu
1
190
VS Code Update for GitHub Copilot
74th
1
300
A2A プロトコルを試してみる
azukiazusa1
2
1.1k
関数型まつり2025登壇資料「関数プログラミングと再帰」
taisontsukada
2
850
Claude Codeの使い方
ttnyt8701
1
130
GitHub Copilot and GitHub Codespaces Hands-on
ymd65536
1
110
Enterprise Web App. Development (2): Version Control Tool Training Ver. 5.1
knakagawa
1
120
設計やレビューに悩んでいるPHPerに贈る、クリーンなオブジェクト設計の指針たち
panda_program
6
1.2k
Featured
See All Featured
Dealing with People You Can't Stand - Big Design 2015
cassininazir
367
26k
Helping Users Find Their Own Way: Creating Modern Search Experiences
danielanewman
29
2.7k
Building a Modern Day E-commerce SEO Strategy
aleyda
41
7.3k
Sharpening the Axe: The Primacy of Toolmaking
bcantrill
44
2.4k
実際に使うSQLの書き方 徹底解説 / pgcon21j-tutorial
soudai
PRO
181
53k
Measuring & Analyzing Core Web Vitals
bluesmoon
7
490
Faster Mobile Websites
deanohume
307
31k
Building Adaptive Systems
keathley
43
2.6k
XXLCSS - How to scale CSS and keep your sanity
sugarenia
248
1.3M
Code Review Best Practice
trishagee
68
18k
Exploring the Power of Turbo Streams & Action Cable | RailsConf2023
kevinliebholz
33
5.9k
Refactoring Trust on Your Teams (GOTO; Chicago 2020)
rmw
34
3k
Transcript
「2024年版 Kotlin サーバーサイドプログラミング 実践開発」の補講 〜O/Rマッパー編〜 2024年7月18日 Server-side Kotlin Night 2024/07
竹端 尚人
自己紹介
竹端 尚人 主にバックエンドエンジニア Twitter: @n_takehata • 2006.04〜 公務員 • 2007.12〜
SES • 2011.04〜 モバイルゲーム開発(サーバーサイド Kotlinを始める) • 2020.12〜 フリーランス(バックエンド開発、 テックリード、技術顧問など) 概要 現在は主に、クラウド型電子カルテを開発している株式 会社ヘンリーでエンジニアとして従事 Kotlin愛好会というコミュニティの運営もやっています
Kotlin愛好会も明日やります!
• CEDEC 2018、2019登壇 • Software Design 2019年2月号〜4月号で短期連載 「サーバーサイド開発の品質を向上させる Java→Kotlin移行のススメ」執筆 •
2021年4月 書籍「Kotlin サーバーサイドプログラ ミング実践開発」出版 • 2023年4月 Techpitにて「Kotlin入門ガイドー言語 思想から特徴・歴史・使いどころまで、まるっと予 備知識がわかる教科書」執筆 • Kotlin Fest 2024登壇 登壇、執筆
2024年版 Kotlin サーバーサイドプログラミング実践開発
Kotlin Fest 2024で話した内容から、 盛り上がったO/Rマッパーについて深堀って話します
Kotlin Fest 2024の発表資料はこちら https://speakerdeck.com/n_takehata/kotlin-s erver-side-programming-practice-2024
アジェンダ 1. Kotlin Fest 2024の振り返り 2. 各種O/Rマッパーのおさらい 3. 色々なSQLを実装してみる 4.
まとめ
アジェンダ 1. Kotlin Fest 2024の振り返り 2. 各種O/Rマッパーのおさらい 3. 色々なSQLを実装してみる 4.
まとめ
1. Kotlin Fest 2024の振り返り
「2024年版 Kotlin サーバーサイドプログラミング 実践開発」 の内容
• 「Kotlin サーバーサイドプログラミング実践開発」の 内容紹介 • 現在のサーバーサイドKotlinで使えるフレームワークの 紹介(Web、DI、O/Rマッパー、テスト) • 今Kotlinでアプリケーションを作る場合のフレームワー ク選定の紹介
「2024年版 Kotlin サーバーサイドプログラミング 実践開発」 の内容
• Ktor(Webアプリケーションフレームワーク) • Koin(DIフレームワーク) • JOOQ(O/Rマッパー) • Kotest(テストフレームワーク)
RepositoryImpl O/Rマッパー (JOOQ) ドメイン オブジェクト Repository Test (Kotest) Service Controller
(Ktor) DI(Koin)
Ask the Speaker、懇親会で O/Rマッパーの話で盛り上がった
• セッションでも「O/Rマッパーが一番迷った」と話して いた • 「O/Rマッパーだけは何使おうか迷うんですよね」とい う悩みが多かった • SQLに近い形で書ける方がいいという意見に「やっぱ りそうですよね」というリアクション O/Rマッパーの話で盛り上がった
結局エンジニアはSQLを書きたい(人が多い)
なぜエンジニアはSQLを書きたいのか?
• 結局「こういうSQLを書きたいからコードは・・・」 という順序で考えている • テーブル設計を意識してデータを扱うのに、SQLだけ 抽象化しても混乱する • テーブルもSQLも意識せず「こういうデータが欲し い」を考えるだけにできないと抽象化の意味がない なぜエンジニアはSQLを書きたいのか?
結局エンジニアはSQLを書きたい(人が多い) 書きたいわけではないけど、いい具合に抽象化された ソリューションがない?
今回は各種O/Rマッパーで色々なSQLの 実装方法を紹介します
参考: Kotlin Fest 2024登壇の振り返り(ブログ) https://blog.takehata-engineer.com/entry/loo k-back-at-kotlin-fest-2024
アジェンダ 1. Kotlin Fest 2024の振り返り 2. 各種O/Rマッパーのおさらい 3. 色々なSQLを実装してみる 4.
まとめ
2. 各種O/Rマッパーのおさらい
• Exposed • JOOQ • Ktorm Kotlin Fest 2024で紹介したO/Rマッパー
Exposed
• JetBrains社が開発しているKotlin製のO/Rマッパー • SQLライクに実装できるDSL、軽量なDAOという2つの アクセス方法が用意されている • 長い間0.x系が続いていたが、2024年中に1.0になるこ とが予定されている Exposedとは?
JOOQ
• SQLに近いDSLでのクエリ作成が可能 • テーブルスキーマからのコード生成が可能で、もとも とJavaのO/RマッパーだがKotlinのコード生成にも対応 している • R2DBCによるノンブロッキングI/Oにも対応 JOOQとは?
Ktorm
• 純粋なJDBCに基づいたKotlin用の軽量なO/Rマッパー • Kotlin製のサードパーティフレームワーク • 生のSQLに近い形で書ける柔軟なDSLが用意されている Ktormとは?
Kotlin Fest 2024では紹介しなかった その他のO/Rマッパー
• MyBatis • Doma2 • Komapper その他のO/Rマッパー
アジェンダ 1. Kotlin Fest 2024の振り返り 2. 各種O/Rマッパーのおさらい 3. 色々なSQLを実装してみる 4.
まとめ
3. 色々なSQLを実装してみる
• Exposed • JOOQ • Ktorm ※ExposedはSQL DSLを使用します この3つのO/Rマッパーで色々なクエリを書いて 比較していきます
使用するテーブル(RDBはMySQLを使用) CREATE TABLE users ( id varchar(10) NOT NULL, name
varchar(50) NOT NULL, age int NOT NULL, PRIMARY KEY (id) ); CREATE TABLE user_purchase_histories ( id varchar(10) NOT NULL, user_id varchar(10) NOT NULL, purchase_date date NOT NULL, price int NOT NULL, PRIMARY KEY (id) );
基本的なCRUDのクエリ (Kotlin Festからの再掲)
transaction { // Insert Users.insert { it[id] = "kotlin" it[name]
= "Kotlin Fest" it[age] = 3 } // Update Users.update({ Users.id eq "kotlin" }) { it[age] = 4 } // Select val users = Users.select(Users.name, Users.age).where { Users.age greaterEq 3 } // Delete Users.deleteWhere{ id eq "kotlin" } } Exposed
// Insert dslContext.insertInto(USERS) .columns(USERS.ID, USERS.NAME, USERS.AGE) .values("kotlin", "Kotlin Fest", 3)
.execute() // Update dslContext.update(USERS) .set(USERS.AGE, 4) .where(USERS.ID.eq("kotlin")) .execute() // Select val users = dslContext.selectFrom(USERS).where(USERS.AGE.ge(3)).fetch() // Delete dslContext.deleteFrom(USERS) .where(USERS.ID.eq("kotlin")) .execute() JOOQ
// Insert database.insert(Users) { set(it.id, "kotlin") set(it.name, "Kotlin Fest" )
set(it.age, 3) } // Update database.update(Users) { set(it.age, 4) where { it.id eq "kotlin" } } // Select val users = database.from(Users).select().where { Users.age greaterEq 3 } // Delete database.delete(Users) { it.id eq "kotlin" } Ktorm
• Exposedはfromやupdate文のsetなど、キーワードを 削って抽象化している • JOOQはほぼ生のSQLと同じ構文で書ける • Ktormも生のSQLに近いが、fromの位置やinsertで使 うsetキーワードなど、少し差分がある
GROUP BY、ORDER BY、LIMIT、OFFSET
select age, count(*) from USERS group by age order by
count(*) desc limit 3 offset 1;
Users.select(Users.age, Users.id.count()) .groupBy(Users.age) .orderBy(Users.id.count(), SortOrder.DESC) .limit(3, offset = 1) Exposed
dslContext.select(USERS.AGE, count()) .from(USERS) .groupBy(USERS.AGE) .orderBy(count().desc()) .limit(1, 3) .fetch() JOOQ
dslContext.select(USERS.AGE, count()) .from(USERS) .groupBy(USERS.AGE) .orderBy(count().desc()) .limit(3) .offset(1) .fetch() offsetを別で渡すことも可能
database.from(Users) .select(Users.age, count()) .groupBy(Users.age) .orderBy(count().desc()) .limit(1, 3) Ktorm
database.from(Users) .select(Users.age, count()) .groupBy(Users.age) .orderBy(count().desc()) .limit(3) .offset(1) off offsetを別で渡すことも可能
• 3つとも書き方に大きな差分はない • ExposedがFromがない分短いくらい
JOIN
select * from USERS left join USER_PURCHASE_HISTORIES on USERS.id =
USER_PURCHASE_HISTORIES.user_id;
Users.leftJoin( UserPurchaseHistories , { Users.id }, { UserPurchaseHistories.userId } ).selectAll()
Exposed
dslContext.select() .from(USERS) .leftJoin(USER_PURCHASE_HISTORIES) .on(USERS.ID.eq(USER_PURCHASE_HISTORIES.USER_ID)) .fetch() JOOQ
database .from(Users) .leftJoin( UserPurchaseHistories , on = Users.id eq UserPurchaseHistories.userId)
.select() Ktorm
• Exposedはonのキーワードを使わず、少し抽象化して いる • JOOQとKtormは近いが、JOOQの方がonをチェーンし て書いてる分、より生のSQLに近い印象
サブクエリ
select * from USERS where exists( select * from USER_PURCHASE_HISTORIES
where USERS.id = USER_PURCHASE_HISTORIES.user_id );
Users.select(Users.columns) .where { exists( UserPurchaseHistories .select(UserPurchaseHistories.id).where{ Users.id eq UserPurchaseHistories.userId }
) } Exposed
dslContext.selectFrom(USERS) .whereExists( dslContext.selectOne() .from(USER_PURCHASE_HISTORIES) .where(USER_PURCHASE_HISTORIES.USER_ID.eq(USERS.ID)) ) .fetch() JOOQ
database .from(Users) .select() .where { exists( database.from(UserPurchaseHistories) .select(UserPurchaseHistories.id) .where {
UserPurchaseHistories.userId eq Users.id } ) } Ktorm
• JOOQだけwhereExists、selectOneなどの関数があり 少し抽象化されている • ExposedとKtormはwhere→exists→selectの階層に なっており、生のSQLに近い
JOINして絞り込む
select USERS.id, USERS.name, sum(USER_PURCHASE_HISTORIES.price) from USERS left join USER_PURCHASE_HISTORIES on
USERS.id = USER_PURCHASE_HISTORIES.user_id where USERS.age >= 20 group by USERS.id having sum(USER_PURCHASE_HISTORIES.price) >= 3000;
Users.leftJoin(UserPurchaseHistories , { Users.id }, { UserPurchaseHistories .userId }) .select(Users.id,
Users.name, UserPurchaseHistories .price.sum()) .where { Users.age greaterEq 20 } .groupBy(Users.id) .having { UserPurchaseHistories .price.sum() greaterEq 3000 } Exposed
dslContext.select(USERS.ID, USERS.NAME, DSL.sum(USER_PURCHASE_HISTORIES.PRICE)) .from(USERS) .leftJoin(USER_PURCHASE_HISTORIES) .on(USERS.ID.eq(USER_PURCHASE_HISTORIES.USER_ID)) .where(USERS.AGE.ge(20)) .groupBy(USERS.ID) .having(DSL.sum(USER_PURCHASE_HISTORIES.PRICE). ge(BigDecimal(3000)))
.fetch() JOOQ
database .from(Users) .leftJoin(UserPurchaseHistories, on = Users.id eq UserPurchaseHistories .userId) .select(Users.id,
Users.name, sum(UserPurchaseHistories.price)) .where { Users.age greaterEq 20 } .groupBy(Users.id, Users.name) .having { sum(UserPurchaseHistories.price) greaterEq 3000 } Ktorm
• 少し複雑で長いSQLになった分、構文で抽象化してい るExposedの短さがより際立っている • JOOQは生のSQLに近い構文な上、”DSL.”のように書か なければいけないキーワードが多いので長い
アジェンダ 1. Kotlin Fest 2024の振り返り 2. 各種O/Rマッパーのおさらい 3. 色々なSQLを実装してみる 4.
まとめ
4. まとめ
• 書きたいわけではないが、書く以外でいいソリュー ションがない • SQLだけ抽象化された状態では微妙 • 結果SQLっぽく書けるO/Rマッパーが好まれやすい エンジニアはSQLを書きたい?
• ExposedはFROMを省略したりJOINの書き方が簡略化 されたりと、少し短く書けるようになっている • JOOQは一番SQLに近い構文で書ける印象 • KtormもSQLに近いが、句の順序やJOINの書き方など 一部差分がある 各種O/Rマッパーの特性
Have a nice Server-side Kotlin!