web-dev-qa-db-ja.com

@TransactionalアノテーションなしのSpringマネージドトランザクション

Springアノテーションを使用して、次のようにトランザクションを管理しています。

@Transactional(readOnly = true)
public class AlertServiceImpl implements AlertService {

     private AlertDAO alertDAO;

     public List<Alert> getAlerts(){
         List<Alert> alerts = alertDAO.getAlerts();
         return alerts;
     }

}

注釈を忘れたらどうなるのだろうか。

// Oops! Forgot to use transactional annotation 
public class AlertServiceImpl implements AlertService {

    private AlertDAO alertDAO;

    public List<Alert> getAlerts(){
         List<Alert> alerts = alertDAO.getAlerts();
         return alerts;
    }

}

AlertDAOの実装が次の場合:

import org.springframework.orm.hibernate3.support.HibernateDaoSupport;

// no annotation here either
public class HibernateAlertDAO extends HibernateDaoSupport implements AlertDAO {

    public List<Alert> getAlerts(){
         // some implementation details that define queryString

         Query query = getSession().createQuery(queryString);
         List<Alert> alerts = query.list();

         return alerts;
    }

}

Hibernateを使用すると、注釈がなくてもデータベースからデータをフェッチできるようです。

この種の不注意の結果は何ですか?また、起こり得る最悪のシナリオは何ですか?

18

ドキュメント( Spring docs )によると、メソッドまたはインターフェースが「トランザクション対応」(つまり、_<tx:annotation-driven/>_)で構成できることを示すのは単なるメタデータです。

tx:annotation-drivenがあり、_@Transactional_属性がない場合、「デフォルト」のトランザクション性が適用されると思います。

  • 伝播設定は[〜#〜] required [〜#〜]です。
  • 分離レベルは[〜#〜] default [〜#〜]です。
  • トランザクションは読み取り/書き込みです。
  • トランザクションタイムアウトは、デフォルトで基礎となるトランザクションシステムのデフォルトタイムアウトになります。タイムアウトがサポートされていない場合はなしです。
  • any RuntimeExceptionはロールバックをトリガーし、チェックされたExceptionはトリガーしません。

_<tx:annotation-driven />_を使用してトランザクションマネージャーを介してそれを駆動していると仮定すると、_@Transactional_属性が欠落しているということは、readOnlyなどのプロパティを適用できないことを意味します。分離伝播rollbackFornoRollbackForなど。

MVCは少し異なると思います-HibernateセッションはMVCリクエストに直接関連付けられています-つまり、リクエストが受信されるとトランザクションが開始されます。

例に戻ると、HibernateDAOSupportのgetSession()のコードは次のとおりです。

_protected final Session getSession()
    throws DataAccessResourceFailureException, IllegalStateException 
{
    return getSession(this.hibernateTemplate.isAllowCreate());
}
_

次に、次のように呼び出します。

_/**
 * Obtain a Hibernate Session, either from the current transaction or
 * a new one. The latter is only allowed if "allowCreate" is true.
 *.......
 */
protected final Session getSession()
    throws DataAccessResourceFailureException, IllegalStateException {
    return getSession(this.hibernateTemplate.isAllowCreate());
}
_

最終的には:

_/** 
 * ....
 * @param allowCreate whether a non-transactional Session should be created
 * when no transactional Session can be found for the current thread
 * ....
 */
private static Session doGetSession(
    SessionFactory sessionFactory, Interceptor entityInterceptor,
SQLExceptionTranslator jdbcExceptionTranslator, boolean allowCreate)
_

基本的に、Transaction:Sessionは1:1 AFAIKに関連付けられており、トランザクションなしで実行する唯一の方法は、トランザクション性を提供する「ベイクイン」永続層を備えたJBossを使用することです(内部)。 getQuery()の後にgetSession()を呼び出した場合でも、JDBC/Hibernate接続であるため、トランザクションが効果的に発生します。

9
Al Sweetman

あなたのシナリオでは、DAOはトランザクションなしで、おそらく自動コミットで実行されます。

将来この種の間違いを回避し、すべてのサービスをトランザクションで実行する必要がある場合は、次の@Transactionalアノテーションを使用してDAOレイヤーを保護できます。

@Transactional(propagation = MANDATORY)
public class HibernateAlertDAO extends HibernateDaoSupport implements AlertDAO {
   ...
}

このアノテーションは、トランザクションを宣言するためにサービスレイヤーを必要とし、そうでない場合は例外をスローします。

1
hoaz

注釈がないと、ロールバックなどのトランザクションの利点が失われます。

@Transactionalアノテーションを使用すると、多くの挿入と1つの失敗など、複数のデータベース操作を実行しているため、トランザクション内のすべての操作をロールバックして、データに一貫性を持たせることができます。

そのため、DAOではなくサービスに注釈を付けることをお勧めします。

0
pfernandom