spring源码分析——事务的传播机制
1:REQUIRED(默认),如果不配置传播属性,默认就是required属性,如果当前有事务就加入加入该事务 ,如果没有就新创建一个事务
准备两个类,TestOuterService ,TestInnerService,传播属性都是required的
在TestOutService中调用testInnerService的方法:
看看运行结果:抛出异常,数据没有插入,回滚成功
看看源码是否使用了TestOuterService的事务,而把TestInnerService的事务挂起
不是新事务,所以跳过回滚
所以如果外层事务和内层事务都是required的机制的话,会把内层事务挂起,加入到外层事务。
如果把外层事务去掉会怎么样?
运行结果显示:抛出异常,数据没有插入,回滚正常。
我们看一下事务拦截器:
因为TestOuterService没有事务注解配置,所有没有被代理,不会进入事务拦截器,当调用到TestInnerService的时候才会进入事务切面
如果内存和外层的事务都开启,相当于只用外层的事务,内层的事务挂起。
2:Supports,支持使用当前事务,如果当前事务不存在,则不适用事务
从运行结果看:抛出异常,数据插入,说明事务没有生效
看一下拦截器如果工作:
当前没有事务,所以不会进入回滚逻辑:
如果把外层的事务放开,再运行一下:
结果显示,存在事务,数据没有插入,所以supports这个事务看起来和没有注解@Transactional,效果一样。
3:REQUIRES_NEW 创建一个新事务,当前事务存在,就挂起当前事务
TestOuterService类,事务级别为required
运行结果:抛出异常,数据没有插入,回滚正常。
我们从拦截器中看一下工作原理:
内层事务调用抛出异常:
内层调用有事务存在,同时是个新事务,所以会回滚
外层事务,如果抛出异常,也会回滚:
所以required_new 是创建一个新事务,即使外层有事务存在,还是用自己的事务。
4:NOT_SUPPORTS 不支持事务,如果当前有事务,就将事务挂起
运行结果:数据被插入,当前事务被挂起
内层执行后,没有事务存在,同时也不是新事务。
5:MANDATORY:中文翻译为强制,支持使用当前事务,如果当前事务不存在,则抛出Exception
运行结果:数据没有查询,有事务存在,回滚正常。
把外层的事务去掉后:
运行结果:,因为声明为mandatory类型,所以必须存在事务,否则就会抛异常
6:NEVER:无事务执行,如果当前有事务则抛出Exception。
运行结果:抛异常,因为标记传播属性为never,但是外层有事务存在
7:NESTED:嵌套事务,如果当前事务存在,那么在嵌套的事务中执行。如果当前事务不存在,则表现跟REQUIRED一样
总结:
required 和 required_new 一个是当前存在事务就加入,挂起自己的事务;另一个是创建一个新的事务,如果存在事务,挂起存在的事务
supports 和 not_supports 一个是支持当前事务,有就加入,没有则不使用事务;另一个是不支持事务,当前存在事务则挂起
mandatroy 和 never 一个是强势使用事务,没有则抛异常; 一个是不使用事务,有则抛异常
nested:存在就嵌套使用,当前不存在就等同于required的