@Transactionalメソッド内でトランザクションをコミットする際に問題が発生しています:
methodA() {
methodB()
}
@Transactional
methodB() {
...
em.persist();
...
em.flush();
log("OK");
}
MethodA()からmethodB()を呼び出すと、メソッドは正常に渡され、ログに「OK」が表示されます。しかし、その後、私は得る
Could not commit JPA transaction; nested exception is javax.persistence.RollbackException: Transaction marked as rollbackOnly 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:521)
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.Cglib2AopProxy$DynamicAdvisedInterceptor.intercept(Cglib2AopProxy.Java:622)
at methodA()...
getCurrentTransaction().isRollbackOnly()?
のようなものをチェックする方法はありますか?このように、メソッドをステップスルーして原因を見つけることができます。私はついに問題を理解しました:
methodA() {
methodB()
}
@Transactional(noRollbackFor = Exception.class)
methodB() {
...
try {
methodC()
} catch (...) {...}
log("OK");
}
@Transactional
methodC() {
throw new ...();
}
起こるのは、methodB
に正しい注釈が付いていても、methodC
にはないということです。例外がスローされると、2番目の@Transactional
は最初のトランザクションをロールバックのみとしてマークします。
メソッドを@Transactional
としてマークすると、メソッド内で例外が発生すると、周囲のTXがロールバックのみとしてマークされます(キャッチした場合でも)。 @Transactional
アノテーションの他の属性を使用して、次のようなロールバックを防止できます。
@Transactional(rollbackFor=MyException.class, noRollbackFor=MyException2.class)
原因となる例外をすばやく取得するには、再コーディングまたは再構築する必要なしにブレークポイントを設定します
org.hibernate.ejb.TransactionImpl.setRollbackOnly() // Hibernate < 4.3, or
org.hibernate.jpa.internal.TransactionImpl() // as of Hibernate 4.3
そして、通常はインターセプターに向かってスタックに上がります。そこで、キャッチブロックから原因の例外を読み取ることができます。
アプリケーションの実行中にこの例外に苦労しました。
最後に問題はSQLクエリにありました。クエリが間違っていることを意味します。
クエリを確認してください。これは私の提案です
コードの...
セクションでスローおよびキャッチされている例外を探します。ランタイムおよびロールバックアプリケーション例外は、他の場所でキャッチされた場合でも、ビジネスメソッドからスローされるとロールバックを引き起こします。
コンテキストを使用して、トランザクションにロールバックのマークが付けられているかどうかを確認できます。
@Resource
private SessionContext context;
context.getRollbackOnly();
bean.xmlでtransactionmanagerを無効にします
<tx:annotation-driven proxy-target-class="true" transaction-manager="transactionManager"/>
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
これらの行をコメントアウトすると、ロールバックの原因となる例外が表示されます;)
ソリューションの良い説明を見つけました: https://vcfvct.wordpress.com/2016/12/15/spring-nested-transactional-rollback-only/
1)トランザクション制御を実際に必要としない場合、ネストされたメソッドから@Transacionalを削除します。そのため、例外がありますが、バブルアップし、トランザクションに影響を与えることはありません。
または:
2)ネストされたメソッドがトランザクション制御を必要とする場合、例外をスローし、ロールバックのみとしてマークされている場合でも、伝播ポリシーのREQUIRE_NEWとして作成します。呼び出し元は影響を受けません。
productRepositoryに以下のコードを適用します
@Query("update Product set prodName=:name where prodId=:id ") @Transactional @Modifying int updateMyData(@Param("name")String name, @Param("id") Integer id);
一方、junitテストでは以下のコードを適用します
@Test
public void updateData()
{
int i=productRepository.updateMyData("Iphone",102);
System.out.println("successfully updated ... ");
assertTrue(i!=0);
}
それは私のコードでうまく機能しています
@ Transactional importを確認してください
import javax.transaction.Transactional;