doma sqlテンプレートのしくみ

52
Doma SQLテンプレートのしくみ by @nakamura_to

Upload: toshihiro-nakamura

Post on 02-Jul-2015

3.781 views

Category:

Technology


12 download

DESCRIPTION

Doma SQLテンプレートのしくみ

TRANSCRIPT

Page 1: Doma SQLテンプレートのしくみ

Doma SQLテンプレートのしくみ

by @nakamura_to

Page 2: Doma SQLテンプレートのしくみ

@nakamura_to

Page 3: Doma SQLテンプレートのしくみ

Domaとは ?

3

Page 4: Doma SQLテンプレートのしくみ

DBアクセスライブラリ• コンパイル時のコード生成 & チェック

• 2 Way SQL対応テンプレート

• Java 8対応

• 依存ライブラリなし

Page 5: Doma SQLテンプレートのしくみ

デモ

5

Page 6: Doma SQLテンプレートのしくみ

DAOインタフェース example/EmployeeDao.java

@Dao(config = AppConfig.class)public interface EmployeeDao {

@Select Employee selectById(Integer id);}

Page 7: Doma SQLテンプレートのしくみ

SQLファイル META-INF/example/EmployeeDao/selectById.sql

select *from employeewhere id = /* id */0

Page 8: Doma SQLテンプレートのしくみ

コンパイル

• SQLファイルの存在チェック•バインド変数のマッピングチェック• DAO実装クラスの生成

Page 9: Doma SQLテンプレートのしくみ

実行

EmployeeDao employeeDao = new EmployeeDaoImpl();Employee result = employeeDao.selectById(1);

select *from employeewhere id = ?

Page 10: Doma SQLテンプレートのしくみ

Domaの系譜

10

Page 11: Doma SQLテンプレートのしくみ

S2Dao (2004)

DBFlute (2006)

JPA (2006)

S2JDBC (2007)

Doma (2009)

Hibernate 2 (2003)

Page 12: Doma SQLテンプレートのしくみ

S2Daoから継承したこと

2 Way SQL 実装のいらないDAO

Page 13: Doma SQLテンプレートのしくみ

S2Daoから継承しなかったこと

命名規約 SELECT文の自動生成

2 Way SQLの実装/*BEGIN*/WHERE /*IF job != null*/job = /*job*/'CLERK'/*END*/ /*IF deptno != null*/AND deptno = /*deptno*/20/*END*//*END*/

Page 14: Doma SQLテンプレートのしくみ

DBFluteから継承したこと

DateFromTo: 時刻の切捨て/切上げ

Page 15: Doma SQLテンプレートのしくみ

DBFluteから継承しなかったこと

ReplaceSchemaなどの周辺ツール

Page 16: Doma SQLテンプレートのしくみ

S2JDBCから継承したこと

RDBMSの挙動の違いを抽象化する方法

自動生成系SQLの組み立て方

Page 17: Doma SQLテンプレートのしくみ

S2JDBCから継承しなかったもの

ライブラリへの依存 Criteria(流れるインタフェース)

Page 18: Doma SQLテンプレートのしくみ

JPAから継承したもの

アノテーション

Page 19: Doma SQLテンプレートのしくみ

JPAから継承しなかったもの

永続コンテキスト リレーションシップ 遅延ローディング 専用の問い合わせ言語(JPQL)

Page 20: Doma SQLテンプレートのしくみ

なぜ SQLテンプレート を使うべきか?

20

Page 21: Doma SQLテンプレートのしくみ

可読性を高くする• StringBuilderと条件分岐でクエリを組み立てるのは煩雑

StringBuilder buf = new StringBuilder();buf.append("select * from emp");if (id != null) { buf.append(" where id = ?");}String sql = buf.toString();

select * from emp where /*%if e.id != null*/ id = /* e.id */0 /*%end */

Page 22: Doma SQLテンプレートのしくみ

検証しやすくする• StringBuilderで組み立てるとSQLの構文が正しいか検証するのが手間

StringBuilder buf = new StringBuilder();buf.append("select * from emp");if (id != null) { buf.append("where id = ?");}String sql = buf.toString();

select * from emp where /*%if e.id != null*/ id = /* e.id */0 /*%end */

Page 23: Doma SQLテンプレートのしくみ

SQLインジェクションを防ぐ• 検索条件はPreparedStatementの?にバインド

select * from employee where name = /* e.name */'hoge'

select * from employee where name = ?

StringBuilder buf = new StringBuilder();buf.append("select * from emp");if (id != null) { buf.append(" where id = " + id);}String sql = buf.toString();

Page 24: Doma SQLテンプレートのしくみ

メンタルモデルに合わせる• SQLは専用のエディタでDBにつなぎ、小さくちょっとずつ組み立てたい

select * from emp

select * from emp where salary > 1000

select * from emp where salary > 1000 order by name

select name, salary from emp where salary > 1000 order by name

select name, salary from emp where salary > /*e.salary*/0 order by name

Page 25: Doma SQLテンプレートのしくみ

Domaの

SQLテンプレートの 何が良いのか?

Page 26: Doma SQLテンプレートのしくみ

存在しないプロパティアクセスはコンパイルエラー

select * from emp where salary > /*e.hoge*/0

@SelectList<Employee> selectByExample(Employee e);

Page 27: Doma SQLテンプレートのしくみ

条件分岐の間違いはコンパイルエラー

select * from emp where/*%if e.id != null */ id = /* id */0

Page 28: Doma SQLテンプレートのしくみ

広いスコープの条件分岐はコンパイルエラー

/*%if e.name == null */select count(*) from emp/*%else */select * from emp where name = /* e.name */'hoge'/*%end *

select * from emp where /*%if e.name == null */

name = /* e.name */'hoge'/*%else */

andname is null

/*%end *

Page 29: Doma SQLテンプレートのしくみ

SQL構文木の構築と走査

29

Page 30: Doma SQLテンプレートのしくみ

DAOインタフェース

@Dao(config = AppConfig.class) public interface EmpDao {

@Select Emp select(Emp e);

@Select List<Emp> selectList(Emp e); }

Page 31: Doma SQLテンプレートのしくみ

パース

走査

構文木

SQLテンプレート select * from emp where /*%if e.id != null*/ id = /* e.id */0 /*%end */

マッピングや 式言語の文法 チェック

• eはメソッドパラメータに存在する? • id はEmpに存在する? • if と end は対応している?

コンパイル時

Page 32: Doma SQLテンプレートのしくみ

パース

構文木

実行時

走査

SQLテンプレート select * from emp where /*%if e.id != null*/ id = /* e.id */0 /*%end */

SQLの生成 orselect * from emp

select * from emp where id = ?

Page 33: Doma SQLテンプレートのしくみ

パース

構文木

実行時(ページング)

走査

SQLテンプレートselect * from emp where salary > /* e.salary */0

ページング用 構文木

変換

SQLの生成select * from emp where salary > ?offset 10 limit 100

Page 34: Doma SQLテンプレートのしくみ

パース

構文木

実行時(悲観的ロック)SQLテンプレート select * from emp where

id = /* e.id */0

変換

悲観的ロック用 構文木

SQLの生成select * from emp where id = ?for update

走査

Page 35: Doma SQLテンプレートのしくみ

なぜ構文木を構築する?

SQLを変換したい コンパイル時と実行時で異なる処理をしたいが、できるだけ共通化したい

Page 36: Doma SQLテンプレートのしくみ

RDBMSのSQL方言対応

パース時はRDBMSごとのSQL方言を考慮せず、共通的なノードのみ押さえる 変換(ページング、悲観的ロック)のみを方言ごとに実行できるようにする 新しい方言への対応は容易な作り

Page 37: Doma SQLテンプレートのしくみ

構築と変換データ構造

Page 38: Doma SQLテンプレートのしくみ

SQLファイル

select * from emp where /*%if e.id != null*/ id = /* e.id */0 /*%end */

Page 39: Doma SQLテンプレートのしくみ

Anonymous

SelectStatement

WordSpace SpaceWord

from emp

SelectClause WhereClauseFromClause

Word Space Other Space

select *

If End /*%end *//*%if e.id != null */

Word

0

Space Word Space Other BindVariableSpace Space

!=id /* e.id */

IfBlockSpaceWord

where

木の構築

Page 40: Doma SQLテンプレートのしくみ

Fragment

Fragmentoffset 10

limit 100

If

Anonymous

SelectStatement

SelectClause WhereClause

IfBlock

End

Word Space Other

FromClause

WordSpace Space SpaceSpace Word

Space Word Space Other BindVariableSpace Space

select * from emp

!=id /* e.id */

/*%end */

Word

0

/*%if e.id != null */

Word

where

木の変換(ページング)

OrderByClause

Page 41: Doma SQLテンプレートのしくみ

If

Anonymous

SelectStatement

SelectClause WhereClause

IfBlock

End

Word Space Other

FromClause

WordSpace Space SpaceSpace Word

Space Word Space Other BindVariableSpace Space

select * from emp

!=id /* e.id */

/*%end */

Word

0

/*%if e.id != null */

Word

where

木の変換(悲観的ロック)

ForUpdateClause

for update

Word

Page 42: Doma SQLテンプレートのしくみ

スペースを保つ

スタイルの維持 行や列数の報告

Page 43: Doma SQLテンプレートのしくみ

式言語の構築と走査

43

Page 44: Doma SQLテンプレートのしくみ

Anonymous

SelectStatement

WordSpace SpaceWord

from emp

SelectClause WhereClauseFromClause

Word Space Other Space

select *

If End /*%end *//*%if e.id != null */

Word

0

Space Word Space Other BindVariableSpace Space

!=id /* e.id */

IfBlockSpaceWord

where

Page 45: Doma SQLテンプレートのしくみ

NeOperator

FieldOperator Literal

木の構築

idVariable

null

!=

e

e.id != null

FieldOperator

idVariable

e

e.id

• コンパイル時にも実行時にも走査

Page 46: Doma SQLテンプレートのしくみ

まとめ

46

Page 47: Doma SQLテンプレートのしくみ

まとめ• DomaのSQLテンプレートはコンパイル時チェックが可能

• SQLの構文木と式言語の構文木を構築してチェック

• 新しいRDMBSへの対応は容易

Page 48: Doma SQLテンプレートのしくみ

ハックして何か新しい機能を!

Page 49: Doma SQLテンプレートのしくみ

参考情報

49

Page 50: Doma SQLテンプレートのしくみ

GitHub Repository

https://github.com/domaframework/doma

Page 51: Doma SQLテンプレートのしくみ

Doma 2 Java 8 時代のDBアクセス

https://nakamura-to.github.io/presentation-doma2-with-java8/

Page 52: Doma SQLテンプレートのしくみ

Thank you