不久前,为了避免事务的嵌套,刻意去修改以前的设计,导致各部分之间经常出现职责的混淆和重复,颇为头痛.今天在一篇名为《解惑 spring 嵌套事务》文章中找到了答案.
原因出在没有能够深刻理解事务声明中不同事务传播属性配置的的含义.原来想象是这样的(见下面示例代码),serviceA和ServiceB的所有方法都被配置声明事务,当serviceA的方法调用ServiceB的方法,我便"顺理成章"的认为methodA和methodB都各自有自己的事务,这会带来两个问题:1)性能下降;2)methodB事务提交后,methodA因异常而回滚,methodB去无法回滚.
ServiceA {
/**
* 事务属性配置为 PROPAGATION_REQUIRED
*/
voidmethodA() {
ServiceB.methodB();
}
}
ServiceB {
原文http://www.iteye.com/topic/35907 全面解释
/**
* 事务属性配置为 PROPAGATION_REQUIRES_NEW
*/
voidmethodB() {
}
}
如果理解了事务传播属性的含义就不会出现这样的误解.见下方解释:
PROPAGATION_REQUIRED -- 支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择。
PROPAGATION_SUPPORTS -- 支持当前事务,如果当前没有事务,就以非事务方式执行。
PROPAGATION_MANDATORY -- 支持当前事务,如果当前没有事务,就抛出异常。
PROPAGATION_REQUIRES_NEW -- 新建事务,如果当前存在事务,把当前事务挂起。
PROPAGATION_NOT_SUPPORTED -- 以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
PROPAGATION_NEVER -- 以非事务方式执行,如果当前存在事务,则抛出异常。
PROPAGATION_NESTED -- 如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则进行与PROPAGATION_REQUIRED类似的操作。
前六个策略类似于EJB CMT,第七个(PROPAGATION_NESTED)是Spring所提供的一个特殊变量。
它要求事务管理器或者使用JDBC 3.0 Savepoint API提供嵌套事务行为(如Spring的DataSourceTransactionManager)
其实若事务传播属性配置为PROPAGATION_REQUIRED,上例中的问题根本不会出现.因为根据上方的解释,当methodB执行的时候,当前线程已经开始了一个事务,所以methodB是不会产生新的事务,也就意味着随之而来的两个问题是不存在的.除非对methodB使用了PROPAGATION_REQUIRES_NEW的配置,才会使得methodB有自己的事务.
关于PROPAGATION_NESTED所指的嵌套,还请参见《解惑 spring 嵌套事务》.
本文转载自:http://zhongl.iteye.com/blog/293161