web-dev-qa-db-ja.com

@Transactional(noRollbackFor = RuntimeException.class)は、RuntimeExceptionでのロールバックを防止しません

_@Transactional (noRollbackFor=RuntimeException.class)
public void methodA (Entity e){
   service.methodB(e);
}
_

---以下のサービス方法---

_@Transactional (propagation=Propagation.REQUIRES_NEW, noRollbackFor=RuntimeException.class)
public void methodB (Entity e){
   dao.insert(e);
}
_

dao.insert(e)methodB()が主キー違反を引き起こし、ConstraintViolationExceptionのサブクラスであるRuntimeExceptionをスローした場合、トランザクションは引き続き実行されると思います。使用したnoRollbackForプロパティのためにコミットします。しかし、(methodA上の)外部トランザクションがまだHibernateTransactionManagerによってメッセージとともにロールバックされていることを確認しました。

org.springframework.transaction.UnexpectedRollback例外:トランザクションはロールバックのみとしてマークされているため、ロールバックされました

同様の質問が報告されているのを見つけましたが、これは正確ではありません。

9
ThermalEagle

例外がキャッチされたら、 Hibernate Session を破棄し、トランザクションをロールバックする必要があります。

セッションが例外をスローした場合、トランザクションをロールバックしてセッションを破棄する必要があります。例外が発生した後、セッションの内部状態がデータベースと一致しない場合があります。

したがって、noRollbackForは、例外をスローする可能性のあるサービスレイヤーとDAOレイヤーに適用されます。 Hibernate DAOを介してデータベースに書き込み、emailServiceを介して電子メールを送信するgatewayServiceがあるとします。 emailServiceがSendMailFailureExceptionをスローした場合、この例外をキャッチしたときにロールバックしないようにgatewayServiceに指示できます。

@Transactional(noRollbackFor=SendMailFailureException.class)
public void saveAndSend(Entity e){
   dao.save(e);
   emailService.send(new Email(e));
}
15
Vlad Mihalcea