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を使用すると、注釈がなくてもデータベースからデータをフェッチできるようです。
この種の不注意の結果は何ですか?また、起こり得る最悪のシナリオは何ですか?
ドキュメント( Spring docs )によると、メソッドまたはインターフェースが「トランザクション対応」(つまり、_<tx:annotation-driven/>
_)で構成できることを示すのは単なるメタデータです。
tx:annotation-drivenがあり、_@Transactional
_属性がない場合、「デフォルト」のトランザクション性が適用されると思います。
_<tx:annotation-driven />
_を使用してトランザクションマネージャーを介してそれを駆動していると仮定すると、_@Transactional
_属性が欠落しているということは、readOnly、などのプロパティを適用できないことを意味します。分離、伝播、rollbackFor、noRollbackForなど。
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接続であるため、トランザクションが効果的に発生します。
あなたのシナリオでは、DAOはトランザクションなしで、おそらく自動コミットで実行されます。
将来この種の間違いを回避し、すべてのサービスをトランザクションで実行する必要がある場合は、次の@Transactional
アノテーションを使用してDAOレイヤーを保護できます。
@Transactional(propagation = MANDATORY)
public class HibernateAlertDAO extends HibernateDaoSupport implements AlertDAO {
...
}
このアノテーションは、トランザクションを宣言するためにサービスレイヤーを必要とし、そうでない場合は例外をスローします。
注釈がないと、ロールバックなどのトランザクションの利点が失われます。
@Transactionalアノテーションを使用すると、多くの挿入と1つの失敗など、複数のデータベース操作を実行しているため、トランザクション内のすべての操作をロールバックして、データに一貫性を持たせることができます。
そのため、DAOではなくサービスに注釈を付けることをお勧めします。