kuniku’s diary

はてなダイアリーから移行(旧 d.hatena.ne.jp/kuniku/)、表示がおかしな箇所はコメントをお願いします。記載されている内容は日付およびバージョンに注意してください。直近1年以上前は古い情報の可能性が高くなります。

iBatisのトランザクション制御

iBatis自身が提供するデータソースからコネクションを取得し
データベースの更新を行う場合に、同一Thread内でのコミットはSqlMapClient.commitTransaction()を
呼び出すまでコミットされない?

  • 同一Thread内でコネクションを新たに取得しても、トランザクションが開始されていると 先にトランザクション処理を開始したものに紐尽く。
  • コネクションがThreadLocalとして管理される。
SqlMapClient sqlMap = SqlMapClientBuilder.buildSqlMapClient(reader);
try {
  sqlMap .startTransaction();
  sqlMap.update (〜〜〜);・・・(A)
  sqlMap.insert (〜〜〜);・・・(B)
  sqlMap.commitTransaction();
} finally {
  sqlMap.endTransaction();
}

Aの後に、コネクションを取得し、Bを別にコミットさせたいとしても無理(別Threadにすればよい?ここは未調査)みたい。
(ネストしたトランザクションが無理なのか。)
SpringなどのDIコンテナ使って、Service層を別にして
それぞれでトランザクション制御(新たにコネクション取得とか、ネストしたトンらザクションを可能とか)しないと無理っぽい。

なので、iBatis提供のデータソースでRowHandlerの

public void handleRow(Object row) {

}

内で、DBに対して更新をかけるような場合は、注意が必要。

Developer Guide iBATIS Data Mapper 2.0 の59ページでは

Note! トランザクションは、入れ子にできません。
同一スレッド内で、commit()やrollback()をコールする前に、
一度以上、startTransaction()をコールすると、例外がスローされます。
要するに、各スレッド内は、SqlMapClientインスタンスに対して、
一つのトランザクションだけ持つことができます。

Note! SqlMapClientのトランザクションは、
JavaのThreadLocalで保持しているトランザクションオブジェクトを利用します。
これは、スレッド同士でお互い別のstartTransaction()をコールでき、
ユニークなコネクションをトランザクションで利用できることを意味しています。

とある。