53
やっぱり SQL 書きたい派に送る jOOQ 第九回 #渋谷java on 2014-12-13 Yusuke Ikeda(@yukung)

やっぱり SQL を書きたい派に送る jOOQ

Embed Size (px)

Citation preview

Page 1: やっぱり SQL を書きたい派に送る jOOQ

やっぱり SQL を

書きたい派に送る jOOQ第九回 #渋谷java on 2014-12-13

Yusuke Ikeda(@yukung)

Page 2: やっぱり SQL を書きたい派に送る jOOQ

$ whoami• 池田 裕介

• @yukung : http://yukung.hatenablog.com/

• 道玄坂の方の緑の会社でジャバとか Node.js とか

Cassandra とか

• 会社では golang 流行ってて乗り遅れ…

• Groovy とか Gradle がすきです

Page 3: やっぱり SQL を書きたい派に送る jOOQ

本題

Page 4: やっぱり SQL を書きたい派に送る jOOQ

jOOQ ご存じですか

Page 5: やっぱり SQL を書きたい派に送る jOOQ

ちょっとした案件にて• とあるマスタ情報を返す Web API

• マスタメンテナンスのバッチ

• 期間1ヶ月程度であんまり時間ない

• 自分1人だけ

• 作ったら引き継ぎする予定で、性質的に頻繁にメンテされるものではない

Page 6: やっぱり SQL を書きたい派に送る jOOQ

弊社 Java プロジェクトの鉄板構成

• Spring Framework

• Tomcat

• MyBatis 3

• MySQL

Page 7: やっぱり SQL を書きたい派に送る jOOQ

(´ヘ`;)ウーム…

Page 8: やっぱり SQL を書きたい派に送る jOOQ

まぁ引き継ぎ考えたら堅いけどね…

Page 9: やっぱり SQL を書きたい派に送る jOOQ

でもぶっちゃけ

Page 10: やっぱり SQL を書きたい派に送る jOOQ

(゚⊿゚)ツマンネモチベーション大事ですよね…?

Page 11: やっぱり SQL を書きたい派に送る jOOQ

というわけで

Page 12: やっぱり SQL を書きたい派に送る jOOQ

軸はあまり変えずに今っぽく

• Spring Framework

• Tomcat

• MyBatis 3

• MySQL

Page 13: やっぱり SQL を書きたい派に送る jOOQ

軸はあまり変えずに今っぽく

• Spring Framework

• Tomcat

• MyBatis 3

• MySQL

• Spring Boot

• Dropwizard と迷ったけど、ちょっと停滞気味?

• (Embedded Tomcat/Jetty)

• ???

• MySQL

Page 14: やっぱり SQL を書きたい派に送る jOOQ

みなさんなら???のとこ何選びますか?

Page 15: やっぱり SQL を書きたい派に送る jOOQ
Page 16: やっぱり SQL を書きたい派に送る jOOQ

• そのまま MyBatis でええやん派

Page 17: やっぱり SQL を書きたい派に送る jOOQ

• そのまま MyBatis でええやん派

• 後述

Page 18: やっぱり SQL を書きたい派に送る jOOQ

• そのまま MyBatis でええやん派

• 後述

• JPA だろ標準だし jk 派

Page 19: やっぱり SQL を書きたい派に送る jOOQ

• そのまま MyBatis でええやん派

• 後述

• JPA だろ標準だし jk 派

• JPA/Hibernate はハマった話の方がよく聞く

Page 20: やっぱり SQL を書きたい派に送る jOOQ

• そのまま MyBatis でええやん派

• 後述

• JPA だろ標準だし jk 派

• JPA/Hibernate はハマった話の方がよく聞く

• ここはビズリーチだぞ DBFlute だろ空気読めよ

Page 21: やっぱり SQL を書きたい派に送る jOOQ
Page 22: やっぱり SQL を書きたい派に送る jOOQ

• Doma 一択派

Page 23: やっぱり SQL を書きたい派に送る jOOQ

• Doma 一択派

• Doma 良かったんだけど、S2Dao 経験してる人居なくて決め手に欠けるのと、Lombok と相性悪くて諦めた(APT 絡みで)

Page 24: やっぱり SQL を書きたい派に送る jOOQ

• Doma 一択派

• Doma 良かったんだけど、S2Dao 経験してる人居なくて決め手に欠けるのと、Lombok と相性悪くて諦めた(APT 絡みで)

• 同じ理由で QueryDSL も諦めた

Page 25: やっぱり SQL を書きたい派に送る jOOQ

知見

https://twitter.com/gakuzzzz/status/443924561961037824https://twitter.com/gakuzzzz/status/443925068486164480

Page 26: やっぱり SQL を書きたい派に送る jOOQ

知見

https://twitter.com/gakuzzzz/status/443382960935284736

Page 27: やっぱり SQL を書きたい派に送る jOOQ

先日 @cero_t さんがこんな Tweet を

Page 28: やっぱり SQL を書きたい派に送る jOOQ

http://d.hatena.ne.jp/cero-t/20141212/1418339302

Page 29: やっぱり SQL を書きたい派に送る jOOQ

なんという昨日の俺

Page 30: やっぱり SQL を書きたい派に送る jOOQ

やっぱり SQL

書きたい派

Page 31: やっぱり SQL を書きたい派に送る jOOQ

あと私 MyBatis が

好きじゃない

Page 32: やっぱり SQL を書きたい派に送る jOOQ

MyBatis で 実際に見たコード

@Select({ "SELECT ", "isbn,", "author_id,", "title,", "publish_date,", "create_date,", "update_date ", "FROM ", "book ", "WHERE ", "author_id = #{authorId} ", "AND ", "#{publishDate} = publish_date" }) Book select(@Param("authorId") long authorId, @Param("publishDate") Date publishDate);

Page 33: やっぱり SQL を書きたい派に送る jOOQ

MyBatis で 実際に見たコード

@Select({ "SELECT ", "isbn,", "author_id,", "title,", "publish_date,", "create_date,", "update_date ", "FROM ", "book ", "WHERE ", "author_id = #{authorId} ", "AND ", "#{publishDate} = publish_date" }) Book select(@Param("authorId") long authorId, @Param("publishDate") Date publishDate);

• 保存したら崩れたんだけど…フォーマッタどこや • 修正入れてテスト実行した時に SQLException とかよく見る • 調査するのにクエリコピペするのめんどくさすぎる

Page 34: やっぱり SQL を書きたい派に送る jOOQ

クエリビルダーあるよ

public String selectPersonLike(final String id, final String firstName, final String lastName) { return new SQL() {{ SELECT("P.ID, P.USERNAME, P.PASSWORD, P.FIRST_NAME, P.LAST_NAME"); FROM("PERSON P"); if (id != null) { WHERE("P.ID like ${id}"); } if (firstName != null) { WHERE("P.FIRST_NAME like ${firstName}"); } if (lastName != null) { WHERE("P.LAST_NAME like ${lastName}"); } ORDER_BY("P.LAST_NAME"); }}.toString();

Page 35: やっぱり SQL を書きたい派に送る jOOQ

クエリビルダーあるよ

public String selectPersonLike(final String id, final String firstName, final String lastName) { return new SQL() {{ SELECT("P.ID, P.USERNAME, P.PASSWORD, P.FIRST_NAME, P.LAST_NAME"); FROM("PERSON P"); if (id != null) { WHERE("P.ID like ${id}"); } if (firstName != null) { WHERE("P.FIRST_NAME like ${firstName}"); } if (lastName != null) { WHERE("P.LAST_NAME like ${lastName}"); } ORDER_BY("P.LAST_NAME"); }}.toString(); • 多少マシになったけど相変わらずカラム指定は文字列

• ぶっちゃけ StringBuilder とあんまり違わない…?

Page 36: やっぱり SQL を書きたい派に送る jOOQ

MyBatis Generator があるじゃない!

Page 37: やっぱり SQL を書きたい派に送る jOOQ

MyBatis Generator で 生成した Criteria 使うと

public List<ItemAchievement> findAllByApplicationId(long UserId, long ApplicationId){ ItemAchievementExample ItemAchievementExample = new ItemAchievementExample(); ItemAchievementExample.Criteria criteria = ItemAchievementExample.createCriteria(); criteria.andApplicationIdEqualTo(ApplicationId).andUserIdEqualTo(UserId); String tableSuffix = RoutingPartitionManager.getPartition(UserId).getSuffix(); return ItemAchievementMapper.selectByExample(tableSuffix, ItemAchievementExample); }

Page 38: やっぱり SQL を書きたい派に送る jOOQ

MyBatis Generator で 生成した Criteria 使うと

public List<ItemAchievement> findAllByApplicationId(long UserId, long ApplicationId){ ItemAchievementExample ItemAchievementExample = new ItemAchievementExample(); ItemAchievementExample.Criteria criteria = ItemAchievementExample.createCriteria(); criteria.andApplicationIdEqualTo(ApplicationId).andUserIdEqualTo(UserId); String tableSuffix = RoutingPartitionManager.getPartition(UserId).getSuffix(); return ItemAchievementMapper.selectByExample(tableSuffix, ItemAchievementExample); }

• Example って何や…サンプルっぽいな( ゚д゚)ポカーン • ぱっと見なにしてるか分かりづらい • メソッド名がウソついてたりしてたら…ウッ

Page 39: やっぱり SQL を書きたい派に送る jOOQ

うーむ。悩ましい。

Page 40: やっぱり SQL を書きたい派に送る jOOQ

そこで jOOQ

Page 41: やっぱり SQL を書きたい派に送る jOOQ

http://www.jooq.org/

Page 42: やっぱり SQL を書きたい派に送る jOOQ

特徴• Database First

• 既存の DB スキーマを重視します(レガシーなシステムのスキーマにも対応)

• Typesafe SQL / Fluent API

• コードを見ると一目瞭然。とことんタイプセーフにしようとする意思を感じます。

• Code Generation

• APT ではなく生成ツールを Maven / Gradle などから使います

• Active Records

• POJO や JPA ベースの Entity、イミュータブルな POJO や DAO も設定により自動生成

• and more…

Page 43: やっぱり SQL を書きたい派に送る jOOQ

サンプル

-- Select all books by authors born after 1920, -- named "Paulo" from a catalogue: SELECT * FROM author a JOIN book b ON a.id = b.author_id WHERE a.year_of_birth > 1920 AND a.first_name = 'Paulo' ORDER BY b.title

http://www.jooq.org/doc/3.5/manual/sql-building/sql-statements/dsl-and-non-dsl/

Page 44: やっぱり SQL を書きたい派に送る jOOQ

サンプル

titleResult<Record> result = create.select() .from(AUTHOR.as("a")) .join(BOOK.as("b")).on(a.ID.equal(b.AUTHOR_ID)) .where(a.YEAR_OF_BIRTH.greaterThan(1920) .and(a.FIRST_NAME.equal("Paulo"))) .orderBy(b.TITLE) .fetch(); !

http://www.jooq.org/doc/3.5/manual/sql-building/sql-statements/dsl-and-non-dsl/

Page 45: やっぱり SQL を書きたい派に送る jOOQ

初見の感想• 日本ではほぼ聞かないけど、海外では割と使われている印象

• ドキュメントがかなりしっかりしている(英語)

• jOOQ ユーザーの Screen Cast やブログも結構ある

• Screen Cast 一度見れば使い方はほぼ分かるので、後はドキュメント見つつ

• Stack Overflow にも良QAがたくさん

• ただし答えてるのが作者の Lukas Eder さんばっかりですごい頑張ってる感

Page 46: やっぱり SQL を書きたい派に送る jOOQ

初見の感想• GitHub にも連携ライブラリとのサンプルなど結構ある

• 開発も割と活発(ただしやっぱり Lukas Eder さんだけ頑張ってる感)

• 有料サポートもあるみたい

• Lukas Eder さんは他にも jOOL とか jOOX とか作ってて DSL 厨っぽい

Page 47: やっぱり SQL を書きたい派に送る jOOQ

Demohttps://github.com/yukung/jooq-sample

Page 48: やっぱり SQL を書きたい派に送る jOOQ

使ってリリースした後の知見!

• リリースした後しばらく経ってから Repository 層(Dao 層)のコード見ても、SQL 読めれば大体何やってるかはすぐ分かる

• POJO とのマッピングは .fetchInto(POJO.class) でわりかし空気読んでマッピングしてくれる

• カラム名とフィールド名が対応してない POJO や Join を考慮した POJO にマッピングしたかったら ModelMapper というマッピングライブラリと連携できるのでそれを使う

• Flyway とか Liquibase のようなマイグレーションツールと組合せてコード生成しながら使うのがベストプラクティスっぽい

Page 49: やっぱり SQL を書きたい派に送る jOOQ

必須じゃないけど便利

// Fetch books and format them as CSV String csv = create.selectFrom(BOOK).fetch().formatCSV(); !ID,AUTHOR_ID,TITLE 1,1,1984 2,1,Animal Farm !// Fetch books and format them as JSON String json = create.selectFrom(BOOK).fetch().formatJSON(); !{"fields":[{"name":"field-1","type":"type-1"}, {"name":"field-2","type":"type-2"}, ..., {"name":"field-n","type":"type-n"}], "records":[[value-1-1,value-1-2,...,value-1-n], [value-2-1,value-2-2,...,value-2-n]]}

Page 50: やっぱり SQL を書きたい派に送る jOOQ

未知数なところ• 扱った案件が小規模だったので、パフォーマンスとか気になるところ

• たくさん Join しなきゃいけないようなクエリ投げるプロジェクトで使うとやっぱりカオスる気がする

• これは多分何かで解決するより、テーブルを見直しましょうだと思う

• マッピングや結果セットを Handler や Listener 使ってコールバック内に処理書けたりするけど、やりすぎるとカオスになる気が

• Generation Tool も大分カスタマイズできるけど、やり過ぎない方が良さそう

• Lukas さんがコミットできなくなったらちとアレかも(一応企業としてやってるみたいだけども)

Page 51: やっぱり SQL を書きたい派に送る jOOQ

Conclusion• Java の O/R マッパー色々あるけど、jOOQ もなかなかいいよ!

• とにかく SQL をタイプセーフに書きたいんだ、IDE の補完使ってガシガシ書きたいんだって人にオススメ

• カスタマイズもかなりできるけど、やり過ぎない方がいいと思います

Page 52: やっぱり SQL を書きたい派に送る jOOQ

jOOQ も選択肢に入れてみては?

Page 53: やっぱり SQL を書きたい派に送る jOOQ

ありがとう ございました