【DBFlute】SQL はどう作られてるの?ConditionBean と Behavior の責務
ビズリーチで開いていただいてる隔週の jflute さん勉強会。
先日 DBFlute の ConditionBean のソースコードリーディングをやっていただきました。
ConditionBean のソースコードを読み進める中で、内部構造のこととかいくつか興味深い話があったのでまとめますー。
この記事で扱うこと
DBFlute の表示 SQL
DBFlute 使ってガシガシ DB アクセスしている人ならとても馴染みの深い機能である SQL の表示機能。
例えばこんなコードで欲しいデータを表示させると。。
memberBhv.selectEntity(cb -> { cb.query().setMemberId_Equal(1); cb.query().setMemberName_LikeSearch("S", LikeSearchOption::likePrefix); });
ログにはこんな感じで、対応した SQL が表示されます。
select dfloc.MEMBER_ID as MEMBER_ID, dfloc.MEMBER_NAME as MEMBER_NAME, .... from MEMBER dfloc where dfloc.MEMBER_ID = 1 and dfloc.MEMBER_NAME like 'S%' escape '|'
指定した ConditionBean が期待した通りになっているのか SQL から確認できるという便利な機能です。
この SQL って一体どこで作られているのでしょうか?
実は完全に ConditionBean の責務となっていて ConditionBean 単体で toDisplay メソッドによって SQL を表示させられます!
MemberCB memberCB = new MemberCB(); memberCB.query().setMemberId_Equal(1); memberCB.query().setMemberName_LikeSearch("S", LikeSearchOption::likePrefix); System.out.println(memberCB.toDisplaySql());
本家のドキュメントを見るとこちらに詳細があります。
ConditionBean -> 2WaySQL -> 表示 SQL
さてこの toDisplaySql メソッドの中を見てみるとわかるのですが、ConditionBean から表示 SQL を直接生成しているのではなく一度 2WaySQL に変換しています。
実際に対応する 2WaySQL は次で表示できます。
MemberCB memberCB = new MemberCB(); memberCB.query().setMemberId_Equal(1); memberCB.query().setMemberName_LikeSearch("S", LikeSearchOption::likePrefix); System.out.println(memberCB.getSqlClause().getClause());
表示される 2WaySQL です。
select/*$pmb.selectHint*/ dfloc.MEMBER_ID as MEMBER_ID, dfloc.MEMBER_NAME as MEMBER_NAME, .... from MEMBER dfloc where dfloc.MEMBER_ID = /*pmb.conditionQuery.memberId.fixed.query.equal*/null and dfloc.MEMBER_NAME like /*pmb.conditionQuery.memberName.varying.likeSearch.likeSearch0*/null escape '|'
この 2WaySQL をさらに表示 SQL 変換しているという処理の流れです。
ConditionBean と Behavior の責務
なぜ一度 2WaySQL に変換するのか。。
jflute さんによると、そもそも ConditionBean は指定した絞り込み条件を 2WaySQL に変換することが大きな責務となってるため、それならば 2WaySQL から変換した方が簡単であるためとのことです。
そして生成された 2WaySQL を Behavior クラスに渡して、実行用の SQL に変換し実際に DB に実行してもらうと言う設計になっています。
つまり SQL 生成については という役割分担と言うことです。
なぜ ConditionBean は 2WaySQL を生成して Behavior クラスに渡すのでしょうか?
これは DBFlute は DB に対して SQL を実行するときはバインド変数を使用していますが、その時の変数のパースが 2WaySQL だとやりやすかったため、採用したとのことでした。
ちなみに外だし SQL と比較してみるとどちらも 2WaySQL を生成することを行なっていますが、
- ConditionBean: ConditionBean クラスが 2WaySQL を生成
- 外だし SQL: 開発者が手動で 2WaySQL を生成
という違いになっているとのことです。
まとめ
- 表示 SQL は ConditionBean で生成
- ConditionBean の責務は 2WaySQL を生成すること
- Behavior の責務は 2WaySQL を実行 SQL に変換して実行すること
知っているから即役立つと言ったものでもないですが DBFlute の内部構造のお話でした。