Cayenneのトランザクション

現在、Cayenneトランザクションについて、いろいろと調べています。
CayenneはもともとJTA準拠なんてぜんぜん考えていなくて、トランザクション制御はCayenne自身が行っていました・・っていうか、今でもそうです。ただし、現状ではトランザクション制御はコンテナなど「外部にお任せする」というオプションがつきました。

DataDomain.setUsingExternalTransactions (boolean flag) 

もしくはCayenneModelerでContainer-Managed Transactionsにチェックを入れます。
直接モデルファイルに

<property name="cayenne.DataDomain.usingExternalTransactions" value="true"/>

を挿入してもOKで、いずれもやっている事は同じ事です。

Cayenneにはorg.objectstyle.cayenne.access.Transactionというそのものずばりのクラスがあります。これは抽象クラスで、実際はトランザクション制御を外部に委託する場合にはTransactionのサブクラスであるExternalTransactionが使用され、Cayenneにおまかせする場合はExternalTransactionクラスのサブクラス(Transactionのサブクラスじゃないよ。ややこしいけど)であるInternalTransactionクラスが使用されるようです。
ちなみにExternalTransaction、InternalTransactionはTransactionのインナークラスになってまして、JavaDocには出てきません(涙)。
また、名前はTransactionですが、JTAとは全く関係ありません。



DataContextがデータベースにアクセスするに、DataDomain.createTransaction()メソッドが呼ばれるようになっています。そこでDataDomainにセットされたUsingExternalTransactions属性によりExternalTransactionかInternalTransactionのインスタンスが返ってくるという仕掛けのようです。

で、S2Cayenneの場合、トランザクション制御はSeasarにやらせたい訳で、ExternalTransactionを使用する事になるんですが、こいつは何をするクラスかと言うと・・単純にcommit()やrollback()時にconnectionをcloseするというものです。(内部的にステータスの管理やTransactionDelegeteの通知なども行っているようです。)
トランザクション制御は外部が行うので、自分は基本的には何もしない・・という訳です。考えてみたらそりゃそうなんですけど、JTAのTransactionとCayenneのTransactionが両方登場して、軽くパニックになります・・

と言う訳で、やるべき事はSeasarが与えてくれるDataSourceをCayenneに与えば良い事になります。たぶん。

SeasarのDataSourceをCayenneに与える方法としてもっともスマートそうなのが、org.objectstyle.cayenne.conf.DataSourceFactoryを実装してあげて、これをConfiguration.setDataSourceFactory()してあげます。

これで、Cayenneに外部トランザクションを効かせるための準備は整った・・のかな?