看了网上的培训机构的视频,说了事务传播机制,云里雾里的,TM的还说错了,说的乱七八糟,念课本呢,也没实例,做个毛的培训!!!
事务的实现方式有两种:一种是编程式和声明式。编程式是开发自己控制,比如自己rollback、commit,其实也是调用数据库的事务接口。
声明式就是@Transational开启事务 ,也就是一种AOP实现,生成代理对象,在方法上提交和回滚。默认对RuntimeException和Error回滚,也可以指定异常类型进行回滚。
事务的隔离级别(由低到高):
read uncommitted(一个事务没提交,另一个事务可以读到)
read committed(一个事务提交了,另一个事务才能读到)--在spring中oracle的默认
repeatable read (可重复度)--在spring中mysql的默认级别
serializable(可串行化)
问题1:在spring种如果不加事务@Transactional会怎么样呢?
Controller有两个service,第二个service有插入操作,插入完后运行后面的代码报错了,那么数据库已经提交了数据,造成事务不一致。
解决方法:只要在第二个service里的方法加上@Transactional,这样第二个service中的操作就会回滚。
但是呢?第一个service还是提交了!!
解决:如果第一个service也加上Transational 。
问题2:结果第一个service还是提交了!!!为什么呢,个人理解因为在两个service里是两个不同的事务,因此会提交第一个没报错的service
解决:controller上也加上@Transactional,把这两个service纳入到一个事务里。
问题3:controller中有@Transactional,service1没@Transactional,service2加上@Transactional,这时候service2报错,那service1会提交吗?
不会提交,因为controller上有@Transactional,service1和service2都会纳入事务。
问题4:controller中有@Transactional,如果想让service1提交,service2报错回滚怎么做?
controller加@Transactional,service1加@Transactional(propagation = Propagation.REQUIRES_NEW),servcie2加@Transactional
spring常用的两种传播属性:
1.REQUIRED 如果存在当前事务则用当前事务,如果不存在当前事务,则新建一个事务
2.REQUIRES_NEW 如果当前存在事务则挂起当前事务,开启一个新事务,新事务执行完毕后,唤醒之前挂起的事务,继续执行。如果不存在当前事务,则新建一个事务。
spring默认是REQUIRED ,就是要么一起成功,要么一起失败。
REQUIRES_NEW (培训机构的老师都说错了,真坑!!!)我的理解就是开启一个新的独立事务,也就是说当前@Transational内没报错,就会提交。
Controller的方法上加上@Transactional注解
MyService: REQUIRES_NEW 开启新的事务
MyService2:默认事务传播机制
Mapper
结果:myService插入数据成功,myService2回滚
注意:
1.controller层也要加@Transactional,否则不起作用
参考资料:https://blog.csdn.net/qianxiaopeng/article/details/82427689