事务传播机制
REQUIRED(Spring默认的事务传播类型 required:需要、依赖、依靠):如果当前没有事务,则自己新建一个事务,如果当前存在事务则加入这个事务
当A调用B的时候:如果A中没有事务,B中有事务,那么B会新建一个事务;如果A中也有事务、B中也有事务,那么B会加入到A中去,变成一个事务,这时,要么都成功,要么都失败。(假如A中有2个SQL,B中有两个SQL,那么这四个SQL会变成一个SQL,要么都成功,要么都失败)
SUPPORTS(supports:支持;拥护):当前存在事务,则加入当前事务,如果当前没有事务,就以非事务方法执行
如果A中有事务,则B方法的事务加入A事务中,成为一个事务(一起成功,一起失败),如果A中没有事务,那么B就以非事务方式运行(执行完直接提交);
MANDATORY(mandatory:强制性的):当前存在事务,则加入当前事务,如果当前事务不存在,则抛出异常。
如果A中有事务,则B方法的事务加入A事务中,成为一个事务(一起成功,一起失败);如果A中没有事务,B中有事务,那么B就直接抛异常了,意思是B必须要支持回滚的事务中运行
REQUIRES_NEW(requires_new:需要新建):创建一个新事务,如果存在当前事务,则挂起该事务。
B会新建一个事务,A和B事务互不干扰,他们出现问题回滚的时候,也都只回滚自己的事务;
NOT_SUPPORTED(not supported:不支持):以非事务方式执行,如果当前存在事务,则挂起当前事务
被调用者B会以非事务方式运行(直接提交),如果当前有事务,也就是A中有事务,A会被挂起(不执行,等待B执行完,返回);A和B出现异常需要回滚,互不影响
NEVER(never:从不): 如果当前没有事务存在,就以非事务方式执行;如果有,就抛出异常。就是B从不以事务方式运行
A中不能有事务,如果没有,B就以非事务方式执行,如果A存在事务,那么直接抛异常
NESTED(nested:嵌套的)嵌套事务:如果当前事务存在,则在嵌套事务中执行,否则REQUIRED的操作一样(开启一个事务)
如果A中没有事务,那么B创建一个事务执行,如果A中也有事务,那么B会会把事务嵌套在里面。
光看这么这些字儿新手会懵逼 没关系 我们一个一个慢慢讲:
@Service
public class ServiceAAA {
@Autowired
private ServiceBBB serviceBBB;
@transaction
public void helloA() {
System.out.println("****业务逻辑1****");
serviceBBB.helloB();
System.out.println("****业务逻辑2****");
}
}
看这段代码 服务A 里面 方法helloA去调服务B的方法 然后前后还有A方法的一些业务逻辑。假设 我们给这两个方法都加上了:
@transaction
这时候就是事务里面调用事务。
那么这样执行在mysql中会是什么样呢:
BEGIN:
*****A*****
BEGIN:
****B****
COMMIT;
*****A****
COMMIT;
很遗憾这种嵌套的写法 在mysql里面是不允许的。 这种去mysql执行的时候。
到了第二个BEGIN, 第一个begin就强行结束了。 它不允许事务里面还有事务。
那么spring帮我们做了哪些事呢? 它直接把这俩合二为一 意味着要死大家一起死
BEGIN:
*****A*****
****B****
*****A****
COMMIT;
像这样,两个事务就合并成了一个事务。
这个就叫做事务的融入
下一个
我就是想这两个事务各自独立 互不影响 A回滚了 不影响B B回滚了不影响A.
这个时候 这种情况 spring 或者 mybatis框架怎么解决呢?
BEGIN:
*****A*****
BEGIN:
****B****
COMMIT;
*****A****
COMMIT;
这里要讲一个事务的挂起
什么叫挂起 就是我们从连接池里面拿一个连接去执行A事务,执行到A里面的B事务的时候 将这个线程挂起, 从连接池里面再拿一个连接 去执行B事务,等B事务执行完之后 再触发第一个连接去执行A事务。
好理解把。
然后再说一个事务的嵌套
BEGIN:
*****A*****
BEGIN:
****B****
COMMIT;
*****A****
COMMIT;
刚才不是说这样mysql不能执行吗?是的 所以大神们搞了一个天才的设计就是手动回滚
BEGIN:
*****A*****
保存点a
****B****
回到保存点a
*****A****
COMMIT;
我不用你mysql的回滚机制 我自己搞一个回滚 这个就实现了嵌套。
搞清楚了这三个,上面几个主要的传播机制就好理解了比如:
REQUIRED(Spring默认的事务传播类型 required:需要、依赖、依靠):如果当前没有事务,则自己新建一个事务,如果当前存在事务则加入这个事务
当A调用B的时候:如果A中没有事务,B中有事务,那么B会新建一个事务;如果A中也有事务、B中也有事务,那么B会加入到A中去,变成一个事务,这时,要么都成功,要么都失败。(假如A中有2个SQL,B中有两个SQL,那么这四个SQL会变成一个SQL,要么都成功,要么都失败)
B有事务 但是被一个没有事务的A方法调用 它就自己建一个事务。
如果A B都有那就是上面说的事务的融入 合成一个事务。
SUPPORTS(supports:支持;拥护):当前存在事务,则加入当前事务,如果当前没有事务,就以非事务方法执行
如果A中有事务,则B方法的事务加入A事务中,成为一个事务(一起成功,一起失败),如果A中没有事务,那么B就以非事务方式运行(执行完直接提交);
如果A B都有事务 还是融入 和上面没区别。
关键是如果B有 调用它的A没有, 那么就听大哥的 B的事务作废
MANDATORY(mandatory:强制性的):当前存在事务,则加入当前事务,如果当前事务不存在,则抛出异常。
如果A中有事务,则B方法的事务加入A事务中,成为一个事务(一起成功,一起失败);如果A中没有事务,B中有事务,那么B就直接抛异常了,意思是B必须要支持回滚的事务中运行
还是
如果A B都有事务 还是融入 和上面没区别。
关键是如果B有 调用它的A没有, 那么B不能听大哥的 直接抛异常
告诉调用者 你用一个没有事务注解的方法调用老子 这是不行的
REQUIRES_NEW(requires_new:需要新建):创建一个新事务,如果存在当前事务,则挂起该事务。
B会新建一个事务,A和B事务互不干扰,他们出现问题回滚的时候,也都只回滚自己的事务;
如果A B 都有事务 那么B事务不能和A融入 这时候A事务和B事务各自独立 互补影响