<< Spring iBatis で O/R マッピング | main | hibernate を iBatis に変更:ある大規模サイト >>

iBatis 1+N 関連の SELECT

JUGEMテーマ:インターネット

1+N関連のテーブル、例えば、受注ヘッダーと明細とかの SELECT を iBatis で実現する方法。

1+NのSELECT は、O-Rマッピングの大きな問題の一つです。
単純な解決策として、親レコードを取得する SELECT 文と各親レコードごとに子レコードを取得する SELECT 文を定義して、1+N回、SELECT 文を実行する方法があります。

iBatis でもこの nest したSELECT 文の実行が、基本的な方法とされています。

しかし、この方法は、取得するレコードが多いと、性能面で深刻な問題が発生します。複数のSQL文を繰り返し実行することは、いかに高速なネットワークでも非効率。(データベースアクセスの通信プロトコルは複雑なので、単純なデータ転送に比べ100倍は遅い。)

また、私の環境では、この 1+N SELECT 時の親レコード取得時に、SELECT FOR UPDATE 文が発行され、ロックがかかる、という問題が発生し、大きな問題になりました。
最初は、Spring の宣言トランザクション管理の記述ミスかと思い、格闘しましたが、実は、iBatis 側の機能でした。

論理的には、正しい処理です。親レコード取得時と子レコード取得時には、同じ状態を保障するためには、排他制御(ロック)が必要です。

しかし、実践的には、これは、厳密すぎて、性能面で問題がおきます。

この解決策として、iBatis では、1+N 関連のテーブルを JOIN で、一回の SQL 文で取得する方法が提供されています。

ResultMap に "groupBy キーカラム" を宣言しておくと、 iBatis は、 指定されたカラムをキーにした、1+N 関連のオブジェクト構造に自動的にマッピングしてくれます。
( SQLの GROUP BY 句とは別の、iBatis 定義ファイル中のキーワードです。)

これだと、SQLの実行は一回だし、排他制御も不要なので、とても効率的。
iBatis の開発者ガイドには、この groupBy が、どんな時でも最善の方法とは、限らない、という記述があります。
しかし、私は、groupBy ではなく、 nested ResultMap を使うべきケースは思いつきませんでした。

開発者ガイドに書いてある以上、groupBy 宣言にも、なにか問題があるんだと思うので、ちょっと不安はありますが、今のところ、groupBy 宣言で、 join したSQL文を実行する方法で、うまくいっています。

1+N 関連は、 ORマッピングの弱点だといわれているようですが、iBatis の groupBy 宣言を使えば、オブジェクト側(Java)もDB側(SQL)も、自然に記述でき、あとは iBatis が面倒を見てくれるので、問題はとても簡単になります。

iBatis を採用している理由は、データベース側は、テーブル設計も、SQL文も、データベースとして自然に設計したかったからです。
フレームワークの仕組みや特徴のために、テーブル設計に制約がでるのは本末転倒。
また、SQL文をフレームワークに隠蔽するより、テキストとして明示的に記述する iBatis は、保守性の点で有利だと考えています。

データベースの設計や、SQL文は、開発者から隠すべきではない、と思うんですよね。

コメント
コメントする









この記事のトラックバックURL
トラックバック
calendar
     12
3456789
10111213141516
17181920212223
24252627282930
31      
<< March 2024 >>
システム設計日記を検索
プロフィール
リンク
システム開発日記(実装編)
有限会社 システム設計
twitter @masuda220
selected entries
recent comment
recent trackback
categories
archives
others
mobile
qrcode
powered
無料ブログ作成サービス JUGEM