これが私の問題です:
Java EE/Spring/Hibernateアプリケーションでバッチを実行しています。このバッチは_method1
_を呼び出します。このメソッドは_method2
_を呼び出します。これによりUserException
(RuntimeException
を拡張するクラス)。次のようになります。
_@Transactional
public class BatchService implements IBatchService {
@Transactional(propagation=Propagation.REQUIRES_NEW)
public User method2(User user) {
// Processing, which can throw a RuntimeException
}
public void method1() {
// ...
try {
this.method2(user);
} catch (UserException e) {
// ...
}
// ...
}
}
_
実行が続行されると例外がキャッチされますが、トランザクションが閉じられると_method1
_の終わりに、RollbackExceptionがスローされます。
これがスタックトレースです:
_org.springframework.transaction.TransactionSystemException: Could not commit JPA transaction; nested exception is javax.persistence.RollbackException: Transaction marked as rollbackOnly
at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.Java:476)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.Java:754)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.Java:723)
at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.Java:393)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.Java:120)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.Java:172)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.Java:202)
at $Proxy128.method1(Unknown Source)
at batch.BatchController.method1(BatchController.Java:202)
_
_method2
_がこの例外をスローしていない場合は、正常に機能します。
私が試したこと:
method1
_に@Transactional(noRollbackFor={UserException.class}))
を設定するmethod2
_を試してみてくださいしかし、それは何も変わりませんでした。
ロールバックが発生した別のトランザクションで例外がスローされるため、なぜそれが機能しないのかわかりません。私はこれを見ました: Jpaトランザクションjavax.persistence.RollbackException:rollbackOnlyとしてマークされたトランザクション しかし、それは本当に私を助けませんでした。
誰かが私に手がかりを与えることができれば、私は非常に素晴らしいでしょう。
更新
_propagation=Propagation.REQUIRES_NEW
_(実際には例外を送信しているメソッド)によって呼び出されるメソッドに_method2
_を設定することで、これを機能させました。このメソッドは、私のBatchService
と非常によく似たクラスで定義されています。したがって、_method2
_ではなくこのレベルで機能する理由がわかりません。
method2
_は考慮されないため、_@Transactional
_をパブリックに設定しました。@Transactionalアノテーションは、インターフェイス定義、インターフェイスのメソッド、クラス定義、またはクラスのパブリックメソッドの前に配置できます。
Exception
の代わりにRuntimeException
を使用しようとしましたが(より適切なため)、何も変更されませんでした。それが機能しているとしても、それは奇妙な振る舞いをしているので質問は開いたままであり、なぜそれが本来あるべきように動作しないのかを理解したいと思います。
Springトランザクションは、デフォルトで、トランザクションと例外を処理するプロキシでSpringBeanをラップすることによって機能します。 method2()
からmethod1()
を呼び出すと、このプロキシが完全にバイパスされるため、新しいトランザクションを開始できず、事実上method2()
を呼び出すことになります。 method1()
の呼び出しによって開かれたトランザクションと同じトランザクションから。
逆に、method1()
から別の注入されたBeanのメソッドを呼び出す場合、実際にはトランザクションプロキシのメソッドを呼び出しています。したがって、このエイリアンメソッドがREQUIRES_NEWでマークされている場合、新しいトランザクションがプロキシによって開始され、method1()
で例外をキャッチして、外部トランザクションを再開できます。
これは ドキュメント で説明されています。