没有@Transactional注释的Spring托管事务

时间:2014-01-23 15:07:15

标签: java spring hibernate transactions

我使用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允许我从数据库中获取数据,即使没有注释。

这种疏忽的后果是什么?可能发生的最坏情况是什么?

4 个答案:

答案 0 :(得分:9)

根据文档(Spring docs),它只是元数据,表明方法或界面可以通过“事务感知”(即<tx:annotation-driven/>)来配置。

仅使用 tx:注释驱动且没有@Transactional属性,我相信您会应用“默认”事务性:

  • 传播设置 REQUIRED
  • 隔离级别为 DEFAULT
  • 交易是可读/写的。
  • 事务超时默认为基础事务系统的默认超时,如果不支持超时,则为none。
  • 任何 RuntimeException 会触发回滚,而任何已检查的异常都不会。

假设您使用<tx:annotation-driven />通过事务管理器驱动它,那么错过@Transactional属性意味着您无法应用 readOnly 这样的属性,< em>隔离,传播 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)

从根本上说,一个事务:会话是1:1的AFAIK,并且没有事务运行的唯一方法是使用JBoss,它具有'烘焙'持久层,为您提供事务性(在封面下) 。即使你在getQuery()之后调用getSession(),你仍然可以有效地进行事务,因为它是JDBC / Hibernate连接。

答案 1 :(得分:0)

如果没有注释,就会失去回滚等优点。

使用@Transactional注释,您正在执行多个数据库操作,如许多插入和一个失败,事务中的所有操作都可以回滚以提供数据的一致性。

这也是为什么建议将注释放在不在DAO中的服务中。

答案 2 :(得分:0)

在你的场景中,你的DAO将在没有事务的情况下执行,很可能是自动提交。

如果您希望将来避免此类错误并要求您在事务中运行所有服务,则可以使用以下@Transactional注释来保护DAO层:

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

此注释将要求服务层声明事务,否则将抛出异常。

答案 3 :(得分:-2)

如果你没有放置@transactional注释,那么什么都不会发生基本上@Transactional不是必须放在方法签名的顶部它只是用于在你的事务是只读时通知编译器= true(仅用于数据检索目的) )当它是只读时= false(仅用于插入更新删除操作)