没有@Transactional注释的Spring托管事务
我正在使用Spring注释来管理我的交易,如下所示:
@Transactional(readOnly = true) public class AlertServiceImpl implements AlertService { private AlertDAO alertDAO; public List getAlerts(){ List alerts = alertDAO.getAlerts(); return alerts; } }
我想知道如果忘记注释会发生什么:
// Oops! Forgot to use transactional annotation public class AlertServiceImpl implements AlertService { private AlertDAO alertDAO; public List getAlerts(){ List 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 getAlerts(){ // some implementation details that define queryString Query query = getSession().createQuery(queryString); List alerts = query.list(); return alerts; } }
似乎Hibernate允许我从数据库中获取数据,即使没有注释也是如此。
这种疏忽的后果是什么?可能发生的最坏情况是什么?
根据文档( Spring docs ),它只是元数据,表明方法或接口可以通过“事务感知”(即
)来配置。
仅使用tx:annotation-driven且没有@Transactional
属性,我相信你会应用“默认”事务性:
- 传播设置是必需的 。
- 隔离级别为DEFAULT 。
- 事务是读/写。
- 事务超时默认为基础事务系统的默认超时,如果不支持超时,则为none。
- 任何RuntimeException都会触发回滚,而任何已检查的Exception都不会。
假设您使用
通过事务管理器驱动它,那么错过@Transactional
属性意味着您不能应用诸如readOnly , isolation , propagation , 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,它具有’烘焙’持久层,为您提供事务性(在封面下)。 即使你在getSession()
getQuery()
之后调用getQuery()
,你仍然有效地发生了一个事务,因为它是一个JDBC / Hibernate连接。
如果没有注释,您将失去像回滚这样的事务的优势。
使用@Transactional注释,您正在执行多个数据库操作,如许多插入和一个失败,事务中的所有操作都可以回滚以提供数据的一致性。
这也是为什么建议将注释放在服务中而不是DAO中的原因。
在您的场景中,您的DAO将在没有事务的情况下执行,很可能是自动提交。
如果您希望将来避免这种错误并要求所有服务在事务中运行,您可以使用以下@Transactional
注释保护DAO层:
@Transactional(propagation = MANDATORY) public class HibernateAlertDAO extends HibernateDaoSupport implements AlertDAO { ... }
此注释将要求服务层声明事务,否则将抛出exception。
如果你没有放置@transactional Annotation就不会发生任何事情基本上@Transactional不是必须放在方法签名的顶部它只是用于在你的事务是只读时通知编译器= true(仅用于数据检索目的)和何时它是只读的= false(仅用于插入更新删除操作)