参考:
https://blog.csdn.net/cckevincyh/article/details/54962920
https://blog.csdn.net/qq_37432174/article/details/96020537
事务传播:
https://blog.csdn.net/qq_43354492/article/details/112692000
事务隔离:
https://blog.csdn.net/telundusiji/article/details/106502267
一、原理
Spring的注解式事务,其底层原理是由AOP实现的。
二、传播性
常用第一种。其余根据各自的业务场景进行使用
假设外层事务 Service A 的 Method A() 调用 内层Service B 的 Method B()
PROPAGATION_REQUIRED(spring 默认)
如果ServiceB.methodB() 的事务级别定义为 PROPAGATION_REQUIRED,那么执行 ServiceA.methodA() 的时候spring已经起了事务,这时调用 ServiceB.methodB(),ServiceB.methodB() 看到自己已经运行在 ServiceA.methodA() 的事务内部,就不再起新的事务。
假如 ServiceB.methodB() 运行的时候发现自己没有在事务中,他就会为自己分配一个事务。
这样,在 ServiceA.methodA() 或者在 ServiceB.methodB() 内的任何地方出现异常,事务都会被回滚。
PROPAGATION_REQUIRES_NEW
比如我们设计 ServiceA.methodA() 的事务级别为 PROPAGATION_REQUIRED,ServiceB.methodB() 的事务级别为 PROPAGATION_REQUIRES_NEW。
那么当执行到 ServiceB.methodB() 的时候,ServiceA.methodA() 所在的事务就会挂起,ServiceB.methodB() 会起一个新的事务,等待 ServiceB.methodB() 的事务完成以后,它才继续执行。
他与 PROPAGATION_REQUIRED 的事务区别在于事务的回滚程度了。因为 ServiceB.methodB() 是新起一个事务,那么就是存在两个不同的事务。如果 ServiceB.methodB() 已经提交,那么 ServiceA.methodA() 失败回滚,ServiceB.methodB() 是不会回滚的。如果 ServiceB.methodB() 失败回滚,如果他抛出的异常被 ServiceA.methodA() 捕获,ServiceA.methodA() 事务仍然可能提交(主要看B抛出的异常是不是A会回滚的异常)。
PROPAGATION_SUPPORTS
假设ServiceB.methodB() 的事务级别为 PROPAGATION_SUPPORTS,那么当执行到ServiceB.methodB()时,如果发现ServiceA.methodA()已经开启了一个事务,则加入当前的事务,如果发现ServiceA.methodA()没有开启事务,则自己也不开启事务。这种时候,内部方法的事务性完全依赖于最外层的事务。
三、隔离性
四、注意事项
1、非Publice方法不起作用
2、同一个类内调用不起作用(classA.methorB() -->classA.)
五、分布式事务
现有比较成熟的解决方案是阿里的 Seata 的AT模式 事务,后续再做补充
六、其它知识点
A、事务的四大特性
原子性、隔离性、持久性、一致性
B、脏读,幻读,不可重复读
1、脏读:一个事务可以读取另一个未提交事务的数据。需要注意的是这里针对的是数据本身,可以理解为针对单笔数据。
个人理解:事务A开启进行了查询数据,同时事务B开启,修改了其中一笔数据,但并未提交,这时事务A又进行了查询,这时就有两笔不一样的数据,然后事务B并没有结束,事务B进行了事务回滚,这样事务A就读取了事务B修改后未提交的数据。因为这里出现这种根本原因是未对数据进行提交,就进行了读取。
需进行读提交(Read Committed)就能解决。
2、不可重复读:一个事务进行读取,分别读取到了不同的数据。需要注意的是这里针对的是数据本身,可以理解为针对单笔数据,重点是对数据的修改和删除,所以对行加锁就可以解决。
个人理解:事务A对数据进行查询,这时事物B开启,对其中一笔数据进行了修改,然后进行了提交(这里进行了提交),然后事务A又对数据进行了查询,发现同一笔不同了,所以事务A读取了两笔不同的数据,两次读取同笔数据有了不同的数据。出现这种根本原因是在事务A进行读操作时,其他事务对数据进行了修改。
读提交(Read Committed)是不足以解决的,需进行可重复读(Repeatable read)就能解决。
3、幻读:一个事务进行读取,分别读取到了不同的数据。需要注意的是这里针对的是数据条数,可以理解为针对多笔数据是个数据集,重点是对数据的新增,所以对表加锁就可以解决。
个人理解:事务A对数据进行查询,这时事物B开启,对其中一笔数据进行了新增,然后进行了提交(这里进行了提交),然后事务A又对数据进行了查询,发现查询所得的结果集是不一样的。幻读针对的是多笔记录。读提交(Read Committed)是不足以解决的,需进行Serializable 序列化就能解决。