Spring事务传播机制
一句话总结:使用Spring等容器管理事务,当存在跨方法、跨类的调用时,Spring等容器通过事务传播机制维护事务的统一或事务的调用链。
当我们使用Spring配置文件或注解配置事务时,我们知道Spring通过动态代理技术自动在方法前后注入了事务处理代码,如下:
methodA() { Connection con = null; try{ con = getConnection(); // your business code con.commit(); } catch(RuntimeException ex) { con.rollback(); } finally { closeCon(); } }
那么,如果方法A调用了方法B这种场景Spring会怎样处理呢,按上面所说Spring会自动给方法A和方法B都自动注入事务处理代码,那么方法A和方法B就是两个事务,那若在方法A中出现异常,方法A回滚了,方法B会回滚么?
methodA(){
methodB();
}
为了解决这个问题,要么方法A和方法B是同一个事务,要么Spring需要维护事务的调用链,来控制A事务回滚关联回滚B事务,这就是事务传播机制。具体要使用同一事务还是多个事务调用链可根据业务配置,如下表格,但绝大多数情况采用Required配置维持同一个事务。
传播行为 | 含义 |
---|---|
PROPAGATION_REQUIRED | 表示当前方法必须运行在事务中。如果当前事务存在,方法将会在该事务中运行。否则,会启动一个新的事务 |
PROPAGATION_SUPPORTS | 表示当前方法不需要事务上下文,但是如果存在当前事务的话,那么该方法会在这个事务中运行 |
PROPAGATION_MANDATORY | 表示该方法必须在事务中运行,如果当前事务不存在,则会抛出一个异常 |
PROPAGATION_REQUIRED_NEW | 表示当前方法必须运行在它自己的事务中。一个新的事务将被启动。如果存在当前事务,在该方法执行期间,当前事务会被挂起。如果使用JTATransactionManager的话,则需要访问TransactionManager |
PROPAGATION_NOT_SUPPORTED | 表示该方法不应该运行在事务中。如果存在当前事务,在该方法运行期间,当前事务将被挂起。如果使用JTATransactionManager的话,则需要访问TransactionManager |
PROPAGATION_NEVER | 表示当前方法不应该运行在事务上下文中。如果当前正有一个事务在运行,则会抛出异常 |
PROPAGATION_NESTED | 表示如果当前已经存在一个事务,那么该方法将会在嵌套事务中运行。嵌套的事务可以独立于当前事务进行单独地提交或回滚。如果当前事务不存在,那么其行为与PROPAGATION_REQUIRED一样。注意各厂商对这种传播行为的支持是有所差异的。可以参考资源管理器的文档来确认它们是否支持嵌套事务 |
至于Spring事务传播机制是怎样实现的,作者也没进行深入研究,猜测是将事务对象存储在ThreadLocal中,若配置为Required传播即同一个事务,那么每个方法都返回该事务对象。若配置为多事务传播,那么事务对象要设计成类似LinkArrayList这样的链式数据结构,当回滚时可顺序地、链条式地回滚多个事务。上诉只是作者猜测哈,有兴趣同学可参考引用链接深入研究。
引用:
https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/transaction/annotation/Propagation.html
https://www.ibm.com/developerworks/cn/java/j-master-spring-transactional-use/index.html
https://blog.csdn.net/yaoqinggg/article/details/51772112