Spring 2.5.2 から 4.0.5.RELEASE にアップグレードしようとしていますが、Spring のトランザクション管理が機能しなくなっていることがわかりました。
本番アプリでは、すべてのデータベース操作は @Transactional アノテーション (デフォルト設定) でマークされた Spring Bean を経由します。数年間、これは期待どおりに機能し、RuntimeException がトランザクション境界内でスローされた場合にロールバックが発生しました。ただし、Spring 4.0.5.RELEASE にアップグレードすると、autocommit が true に設定されているように動作します。
スタック トレースを調べて、問題のコードがまだトランザクション プロキシ内で実行されていることを確認しました。しかし、トランザクションに入った直後にテーブルに対して単純な 1 行の更新を実行すると、更新はcommitされます。Spring のバージョンを変更しただけなので、これは不可解です。
自動コミットの動作は、後の Spring バージョンで変更されましたか? 4.05 で行う必要がある追加の構成はありますか?
トランザクション マネージャーの構成は次のとおりです (2.52 と 4.05 の両方のバージョンで同じ)。
<tx:annotation-driven transaction-manager="transactionManager" />
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="efmsDataSource" />
</bean>
<bean id="efmsDataSource" class="com.uprr.eni.commons.dao.OracleDataSource">
<property name="driverClassName" value="oracle.jdbc.OracleDriver" />
<property name="url" value="jdbc:oracle:thin:@${db_instance}.oracle.uprr.com:1521:${db_instance}" />
<property name="username" value="${db_user}" />
<property name="password" value="${db_password}" />
<property name="maxActive" value="8" />
</bean>
コードに @Transactional メソッドを持つ Bean を次に示します。
<bean id="efmsExecutor" class="com.uprr.eni.commons.dao.exec.DataSourceExecutorBean">
<property name="dataSource" ref="efmsDataSource" />
</bean>
アプリケーション コンテキストを作成してトランザクション Bean を取得し、それを静的変数として保存する方法は次のとおりです。
context = new ClassPathXmlApplicationContext(CONFIG_FILES);
efmsExecutorBean = (DataSourceExecutorBean)context.getBean(EFMS_EXECUTOR_BEAN);
その Bean を静的変数に保存し、トランザクションを実行するときに参照します。何か違うことをするべきですか?
トランザクションを開始したいときは、次のように呼び出します。
efmsExecutorBean.executeTransaction(executor);
これは、トランザクションを開始するために DataSourceExecutorBean で呼び出すメソッドです。基本的には、内部データ ソースをエグゼキューター (実際にデータベースの作業を行うコード) に渡すだけです。
@Transactional public void executeTransaction(final DataSourceExecutor executor) {
executor.execute(source); // Perform the unit of work
final StringList errors = executor.getResult().getErrors(); // Did any errors occur?
if (!errors.isEmpty()) { // If so
for (final String error : errors) {
ApiLog.error(error); // Record them
}
throw new ExecutorError(ERROR, executor.getName()); // Abort
}
}
2 つのバージョンのログを再確認したところ、4.0.5 (壊れた) バージョンには、2.5.2 バージョンにはないいくつかのエントリがあることに気付きました。これらのエントリは、トランザクションが開始されるとすぐに表示されます。
2014-07-31 09:34:43,576 [btpool0-0] DEBUG - シングルトン Bean 'efmsDataSource' の共有インスタンスを作成しています 2014-07-31 09:34:43,576 [btpool0-0] DEBUG - Bean 'efmsDataSource' のインスタンスを作成しています2014-07-31 09:34:43,576 [btpool0-0] デバッグ - Bean 'efmsDataSource' を熱心にキャッシュして、潜在的な循環参照を解決できるようにする
おそらく、これで何が起こっているかが説明されます (理由ではありません)。シングルトン データ ソース Bean は実際には singleton ではないようです。Google では、同様の問題を抱えている人が何人か表示されていますが、解決方法は示されていません。これは誰かとベルを鳴らしますか?