UserTransaction開始タイミング

UserTransaction.begin()を呼ぶ前にデータソースを取得しておかなければならないのか,あるいはUserTransaction.begin()を呼んだ後にデータソースを取得するという順番でないとならないのか,これはJ2EE実装依存の話のようだ。

この間はJBossWebLogicかのどちらかの都合にあわせて(詳細失念)beginの前にデータソースを取得するようにテストコードを書いていた.例えばこんな感じである.

InitialContext ctx = new InitialContext();
UserTransaction ut = (UserTransaction) ctx.lookup(Const.USER_TRANSACTION_JNDI);

DataSource ds = (DataSource) ctx.lookup(Const.XADS_JNDI);
Connection conn = ds.getConnection();
conn.setCatalog("test");
Statement stmt = conn.createStatement();

ut.begin();

stmt.executeUpdate("INSERT INTO xasimpletest VALUES (1)");

ut.commit();

ところがWebSphereの場合はこの手順で実行すると次のようなエラーが発生する.

java.lang.IllegalStateException: Cannot start a new UOW. A LocalTransactionContainment is already active with work.
	at com.ibm.ws.LocalTransaction.LTCUOWCallback.uowPreBegin(LTCUOWCallback.java:238)
	at com.ibm.ws.LocalTransaction.LTCUOWCallback.contextChange(LTCUOWCallback.java:154)
	at com.ibm.ws.uow.UOWScopeCallbackManager.notifyCallbacks(UOWScopeCallbackManager.java:62)
	at com.ibm.ws.Transaction.JTA.UserTransactionImpl.begin(UserTransactionImpl.java:162)
	at testsuite.integration.xa.simple.websphere.SingleCommit2Servlet.doGet(SingleCommit2Servlet.java:58)     

CMTなEJBでのことなら納得できるのだが,Servletとかで上記テストコードを走らせてこのエラーがでるとちょっと不思議に思う.

beginとデータソースの順序を以下のように入れ替えるとWebSphereでは上手くいく.(JBossWebLogicのどちらかでうまくいかない,どっちだったっけな・・・)

InitialContext ctx = new InitialContext();
UserTransaction ut = (UserTransaction) ctx.lookup(Const.USER_TRANSACTION_JNDI);

ut.begin();

DataSource ds = (DataSource) ctx.lookup(Const.XADS_JNDI);
Connection conn = ds.getConnection();
conn.setCatalog("test");
Statement stmt = conn.createStatement();

stmt.executeUpdate("INSERT INTO xasimpletest VALUES (1)");

ut.commit();

まあとりあえずこういうメモを残しておこうということで.