TransactionRequiredExceptionエラー

1. 概要

このチュートリアルでは、_TransactionRequiredException_エラーの原因とその解決方法を調べます。

*2. TransactionRequiredException *

*このエラーは通常、トランザクションなしでデータベースを変更するデータベース操作を実行しようとしたときに発生します*。
たとえば、トランザクションなしでレコードを更新しようとすると:
Query updateQuery
  = session.createQuery("UPDATE Post p SET p.title = ?1, p.body = ?2 WHERE p.id = ?3");
updateQuery.setParameter(1, title);
updateQuery.setParameter(2, body);
updateQuery.setParameter(3, id);
updateQuery.executeUpdate();
次の行に沿ってメッセージとともに例外を発生させます。
...
javax.persistence.TransactionRequiredException: Executing an update/delete query
  at org.hibernate.query.internal.AbstractProducedQuery.executeUpdate(AbstractProducedQuery.java:1586)
...

3. トランザクションの提供

*明らかな解決策は、データベース変更操作をトランザクションにラップすることです:*
Transaction txn = session.beginTransaction();
Query updateQuery
  = session.createQuery("UPDATE Post p SET p.title = ?1, p.body = ?2 WHERE p.id = ?3");
updateQuery.setParameter(1, title);
updateQuery.setParameter(2, body);
updateQuery.setParameter(3, id);
updateQuery.executeUpdate();
txn.commit();
上記のコードスニペットでは、トランザクションを手動で開始およびコミットします。 * Spring Boot環境では、__ @ Transactional __annotationを使用してこれを実現できます。*

*4. Spring *でのトランザクションサポート

*よりきめ細かな制御が必要な場合は、Springの_TransactionTemplate_ *を使用できます。 これにより、プログラマーはメソッドのコード実行に進む直前にオブジェクトの永続性をトリガーできます。
たとえば、メール通知を送信する前に投稿を更新するとします。
public void update() {
    entityManager.createQuery("UPDATE Post p SET p.title = ?2, p.body = ?3 WHERE p.id = ?1")
      // parameters
      .executeUpdate();
    sendEmail();
}
*上記のメソッドに__ @ Transactional __を適用すると、更新プロセスの例外にもかかわらず電子メールが送信される可能性があります。*これは、メソッドが終了して呼び出し元に戻ろうとしているときにのみトランザクションがコミットされるためです。
したがって、_TransactionTemplate_内の投稿を更新すると、操作がすぐにコミットされるため、このシナリオは回避されます。
public void update() {
    transactionTemplate.execute(transactionStatus -> {
        entityManager.createQuery("UPDATE Post p SET p.title = ?2, p.body = ?3 WHERE p.id = ?1")
          // parameters
          .executeUpdate();
        transactionStatus.flush();
        return null;
    });
    sendEmail();
}

5. 結論

結論として、トランザクションでデータベース操作をラップすることは一般的に良い習慣です。 データ破損の防止に役立ちます。 完全なソースコードはhttps://github.com/eugenp/tutorials/tree/master/persistence-modules/hibernate5[Github上]で入手できます。