torutkのブログ

ソフトウェア・エンジニアのブログ

JJUGナイトセミナー「Java O/Rマッパー特集」に参加 #jjug

開催案内ページは次です。
【東京】JJUG ナイトセミナー 「Java O/Rマッパー特集」 7/26(水)開催 - 日本Javaユーザーグループ/Japan Java User Group | Doorkeeper

togetterまとめ
【東京】JJUG ナイトセミナー 「Java O/Rマッパー特集」 7/26(水)開催 #jjug - Togetter

30分ずつで4つのO/Rマッパーライブラリの話を聞きました。

25分でわかるJPA(多田真敏さん)

スライド資料:https://speakerdeck.com/masatoshitada/jpa-in-25min

JPAは、JSR338で策定された仕様です。仕様書はPDFで600ページに及ぶ量です。アノテーションとAPIの規定で、JPAを使用するには、JSR338を実装したいずれかのライブラリが必要です。例えば、HibernateやEclipseLinkがあります。本日のセッションはHibernateを用いています。振る舞いには実装固有の差異があるそうです。

JPAは、エンティティとテーブルとを1対1で作るものです。リレーションの1:多など*1に対応しています。

  • Tips:SQLログの出力を必ず設定しよう

状態管理が重要、永続化コンテキストが超重要、このセッションで一番大事なのはエンティティの状態遷移です。

エンティティの作成には、主キーほぼ必須です。
エンティティは、CRUD操作の窓口ではありません。
全フィールドがINSERT対象となり、回避する@Transientアノテーションあり。
merge()は、SELECT + UPDATEが発行されます。

  • 落とし穴:merge は引数に指定したエンティティのコピーが作られ戻り値として返り、これがMANAGEDとなる。引数に指定したエンティティはMANAGEDにならない。

JPQLは、INSERT相当はなく、SELECT/UPDATE/DELETE相当、発行されるSQLは実装依存、副問い合わせはWHERE句とHAVING句。できないことは、INSERT、集合演算、FROM句での副問い合わせ。

フェッチにはEAGER/LAZYあり。EAGERは、HibernateではJOIN、EclipseLinkではSELECTが使われます。

  • 注意点:LAZYフェッチでトランザクション終了後にフェッチすると例外が発生(実装系で振る舞い異なる)
  • 基本はLAZYを使う。
  • JOIN FETCH + DISTINCTでデータ重複を防ぐ

Spring Data JPAはとても便利です。名前はあれですが、Springでなくても使えます。

JPAを使うには、正しい知識と適した状況が必要です。次の3条件をすべて満足していないとJPAの使用でハマります。

  • DBを新規に設計できる
  • 複雑なSQL(集合演算、FROM句の副問い合わせ)が要件にない
  • 「パーフェクトJava EE」(のJPA)を理解している人がプロジェクトにいる

MyBatis を利用した Web Application 開発についてのご紹介(Tokuhiro Matsunoさん)

スライド資料:https://www.slideshare.net/tokuhirom/mybatis-web-application

先ほどのJPAとは対極にある感じのライブラリです。
SQLは直接(手で)記述し、それをinterfaceを通じて呼び出し、結果がBeanに格納されます。java.lang.reflect.Proxyを使って実装されています。

主キーがなくてもOKで、MyBatis前提では作られていないDBでもOK、サブクエリもOK、N+1問題はないです。
直接SQL書くので、DB依存になります(DB依存して問題のないプロジェクトも多いはず)。
SQLの書き方は、1) XML、2)アノテーション、3)JavaのDSL とあります。LINE社内では、1)が7割、2)が3割、最近2)が増えつつあるとのことです。
IntelliJではアノテーションのSQLをうまく認識させられるので記述に便利など。

ざっくりわかるDoma(うらがみさん)

スライド資料:http://backpaper0.github.io/ghosts/doma-zakkuri/#1

アノテーションプロセッシングを使ったライブラリです。
O/RマッパーというよりResultSetマッパーです。
Java SE 8対応で、date and time API、Optional、Stream APIにも対応しています。
SQLは手で書き、クラスパス上にSQLファイルとして置きます。2way SQLと呼び、Doma機能をSQLのコメントで書きます。なのでSQLとして直接実行も可能となります。

ドメインクラスと呼ぶ値オブジェクトにカラムをマッピングできます(オブジェクト指向(DDD)のドメインとは別物)。

コンパイル時にいろいろ検証してくれます。エンティティはイミュータブルにできまます。

できないことは、SELECTクエリの自動生成、親子などの構造のエンティティへのマッピング。

Reladomo入門(伊藤博志さん)

スライド資料:https://www.slideshare.net/itohiro73/reladomo-jjug-jjug

ゴールドマンサックスで2004年頃からエンタープライズに使用、2016年にオープンソース化(APL 2.0)。
マッピングをXMLで定義し、Javaコードを生成(Abstractクラス)。ビジネスロジックは継承したサブクラスに記述する使い方です。
キャッシュ機構が充実しています。
バイテンポラルモデルという時間を2つの観点で扱えるようになっているのがまた優れものです。
GS CollectionをネイティブサポートしているのでデータベースからデータをGS Collectionに放り込んでインメモリで高度なデータ処理ができるようになっているのもよさそうです。GS Collectionは、Eclipse Collectionに寄贈(?)されていますが、そちらへの対応は現在進行中とのことです。

Javaのコードで記述できる、オブジェクト指向の極みのようなO/Rマッパーです。

感想

JPAの使用が適する3つの条件で、データベースに手を入れられる(新規に設計できる)が挙げられていました。既存のリレーショナルデータベースを使ったアプリケーションを開発する際に、JPAでは辛みが出るのでしょう。
HibernateとEclipseLinkとで振る舞いに違いがあるのは今回初めて知りました。
今回のナイトセミナーで、JPAの使いどころが聞けたのが収穫です。

JPAが、O/Rマッパーだとすると、次のMyBatisはごりごりSQLを使うデータベースアクセスライブラリですね。JPAがSQLを隠蔽しているのと違って、SQLを積極的に使っていくライブラリです。

Domaはちょっと使いどころが難しそう。SQLを使うデータベースアクセスライブラリですが、ドメインクラスという名の値オブジェクトとしてデータクラス的なものとデータベースをマッピングしてくれます。ですが値オブジェクトなので・・・。

Reladomoは、データベースへのアクセスをJavaコードからJavaのAPIをどんどん呼ぶように書けることと、バイテンポラルという特色がいいですね。

ということで、SQLを使ってRDBMSを強く意識するライブラリ(MyBatisとDoma)、SQLを隠蔽してRDBMSを意識しないようにするライブラリ(JPA実装ライブラリ、Reladomo)とそれぞれ特色のあるデータベースアクセスライブラリの紹介を聞くことができたのが今回のナイトセミナーのよかったところです。

N+1問題

実は今回のセミナーで初めて聞きました。
調べると、O/Rマッパーでは有名な(深刻な)問題で、Rails界隈での情報がいろいろ出てきました。

*1:@OneToOne, @OneToMany, @ManyToOne, @ManyToMany