S2Daoとのポテンシャル比較
概要
DBFluteとS2Daoとの機能レベルでの違いは、ConditionBeanやBehaviorなど言うまでもない部分があります。 ここではそういった機能の違いではなく、「O/R Mapperとしてのポテンシャル」という面での違いを話題にします。 これはいったいどういうことなのか、説明するよりも読んで頂いた方が早いので早速下記ご覧下さい。パフォーマンス考慮
DB固有のSQLでページングの絞り込みを行う
ページングの実現方法として、ResultSet(Java)やDataReader(C#)での読み飛ばしだけでなく、 極力「DB固有のSQLでページングの絞り込み」を行います。 ConditionBeanのページングでは以下のようになります:
- MySQL -- limit句を利用
- PostgreSQL -- limit/offset句を利用
- Oracle -- rownumを利用
- H2 -- limit/offset句を利用
- Firebird -- first句を利用
- DB2 -- fetch first rows only句を利用 ※offset処理はResultSetにて
- SQLServer -- top句を利用 ※offset処理はResultSetにて
- Derby -- ResultSetにより読み飛ばし
検索結果のマッピングでリフレクションを使わない
一般的にO/Rマッパで懸念されることとして、検索結果をEntityクラスへマッピングする際に利用するリフレクションコストがあります。 環境の向上によって、リフレクションコストは少なくなっていきますが、できることなら避けたいところです。
DBFluteは、自動生成時にDBのメタ情報かr「マッピングする処理」を自動生成し、リフレクションを使わずにマッピングを行います。
SqlRegistryをデフォルトOFFに
詳しくはこちら
メソッド単位での初期化
S2Daoは、アプリケーションが起動してからの初回アクセス時に該当のDaoを初期化します。 DBFluteの初期化することには代わりはありませんが、Daoを丸ごと初期化するのではなく、呼び出されたメソッドだけを初期化します。 これにより、初回アクセス時の「長い待ち」を軽減します。
また、そもそも「アプリケーション起動時に初期化したい」ということもあります。 単体テストは遅延初期化で結合テストや本番起動時は一括初期化という使い分けが現実的かと思われます。 DBFluteは、明示的に一括初期化(ConditionBeanのみ)ができるようになっています。
ex) ConditionBeanを利用するDaoの一括初期化(画面起動時のみ実施するように)
BehaviorSelector behaviorSelector = ...(DI)
behaviorSelector.initializeConditionBeanMetaData();// 一括初期化
デバッグ考慮
デバッグログを重視
詳しくはこちら
例外メッセージの充実
主に外だしSQLの際ですが、パラメータコメントは便利ですがヒューマンエラーが発生します。そのときに発生する例外のメッセージは開発においてとても重要です。 DBFluteは、極力デバッグが速くできるように例外メッセージをカスタマイズしています。
ex) 存在しないプロパティをバインド変数コメントに記載してしまった場合「/*pmb.wrongMemberId*/」
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
The property on the bind variable comment was Not Found!
[Advice]
Please confirm the existence of your property on your arguments.
Abd has the property had misspelling?
[Bind Variable Comment Expression]
pmb.wrongMemberId
[NotFound Property]
com.example.dbflute.basic.dbflute.exdao.pmbean.UnpaidSummaryMemberPmb#wrongMemberId
[Specified SQL]
-- selectBindVariableNotFoundProperty.sql
select member.MEMBER_ID
, member.MEMBER_NAME
, (select sum(purchase.PURCHASE_PRICE)
from PURCHASE purchase
where purchase.MEMBER_ID = member.MEMBER_ID
and purchase.PAYMENT_COMPLETE_FLG = 0
) as UNPAID_PRICE_SUMMARY
, memberStatus.MEMBER_STATUS_NAME
from MEMBER member
left outer join MEMBER_STATUS memberStatus
on member.MEMBER_STATUS_CODE = memberStatus.MEMBER_STATUS_CODE
/*BEGIN*/where
member.MEMBER_ID = /*pmb.wrongMemberId*/3
/*IF pmb.memberName != null*/and member.MEMBER_NAME like /*pmb.memberName*/'ス' || '%'/*END*/
/*IF pmb.memberStatusCode != null*/and member.MEMBER_STATUS_CODE = /*pmb.memberStatusCode*/'FML'/*END*/
/*IF pmb.unpaidMemberOnly*/
and exists (select 'yes'
from PURCHASE purchase
where purchase.MEMBER_ID = member.MEMBER_ID
and purchase.PAYMENT_COMPLETE_FLG = 0
)
/*END*/
/*END*/
order by UNPAID_PRICE_SUMMARY desc, member.MEMBER_ID asc
* * * * * * * * * */
