无需@Transactional注释的 Spring 管理事务

2022-09-01 23:47:07

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

这种粗心大意的后果是什么,可能发生的最坏情况是什么?


答案 1

根据文档(Spring文档),它只是元数据,以指示该方法或接口可以通过“事务感知”(即)来配置。<tx:annotation-driven/>

只有tx:注释驱动并且没有属性,我相信你可以应用“默认”事务性:@Transactional

  • 传播设置是必需的
  • 隔离级别为默认
  • 事务是读/写的。
  • 事务超时默认为基础事务系统的默认超时,如果不支持超时,则为无。
  • 任何运行时异常都会触发回滚,任何选中的异常都不会触发回滚。

假设您正在使用 通过事务管理器驱动它,那么缺少该特性意味着您无法应用诸如readOnly隔离传播rollbackFornoRollbackFor等属性。<tx:annotation-driven />@Transactional

我相信MVC略有不同 - 休眠会话直接绑定到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,它有一个“内置”的持久性层,它为你提供事务性(在幕后)。即使您在调用后仍然有效地发生了事务,因为它是JDBC / Hibernate连接。getQuery()getSession()


答案 2

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

如果你想在将来避免这种错误,并要求所有服务在事务中运行,你可以使用以下注释来保护DAO层:@Transactional

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

此注释将需要服务层来声明事务,否则将引发异常。


推荐