springboot事务及其失效的几种情况
事务的基本原理
Spring事务的本质其实就是数据库对事务的支持,没有数据库的事务支持,spring是无法提供事务功能的。事务是一系列的动作,一旦其中有一个动作出现错误,必须全部回滚,系统将事务中对数据库的所有已完成的操作全部撤消,滚回到事务开始的状态,避免出现由于数据不一致而导致的接下来一系列的错误。事务的出现是为了确保数据的完整性和一致性,在目前企业级应用开发中,事务管理是必不可少的。
事务有四大特性(ACID):1.原子性(Atomicity) 2.一致性(Consistency)3.隔离性(Isolation)4.持久性(Durability)
Spring 事务的传播属性
spring事务的传播属性,就是定义在存在多个事务同时存在的时候,spring应该如何处理这些事务的行为。这些属性在TransactionDefinition中定义,具体常量的解释见下表:
spring事务的隔离级别
事务的隔离性,当多个线程都开启事务操作数据库中的数据时,数据库系统要能进行隔离操作,以保证各个线程获取数据的准确性,在介绍数据库提供的各种隔离级别之前,如果不考虑事务的隔离性,多用户访问数据库,就是所谓的事务的并发。可能存在的问题:1.脏读:一个事务读到另一个事务未提交的更新数据。2.不可重复读:一个事务两次读同一行数据,可是这两次读到的数据不一样。3.幻读:一个事务执行两次查询,但第二次查询比第一次查询多出了一些数据行。4.丢失更新:撤消一个事务时,把其它事务已提交的更新的数据覆盖了。
使用示意:
事务的嵌套
嵌套是子事务在父事务中执行,子事务是父事务的一部分,在进入子事务之前,父事务建立一个回滚点,叫save point,然后执行子事务,这个子事务的执行也算是父事务的一部分,然后子事务执行结束,父事务继续执行。
1)如果子事务回滚,会发生什么?
父事务会回滚到进入子事务前建立的save point,然后尝试其他的事务或者其他的业务逻辑,父事务之前的操作不会受到影响,更不会自动回滚。
2)如果父事务回滚,会发生什么?
父事务回滚,子事务也会跟着回滚!为什么呢,因为父事务结束之前,子事务是不会提交的,我们说子事务是父事务的一部分,正是这个道理。
3)事务的提交,是什么情况?
子事务先提交,父事务再提交。子事务是父事务的一部分,由父事务统一提交。
Spring boot事务失效的几种情况
1.内部调用:使用一个没有事务的方法调用一个有事务的方法,失败后不会进行回滚。
2. .没有指定监听的Exception:@Transactional只会监听RuntimeException,当抛出其他异常时,不能正常捕获,也就不会回滚。
解决方法:
手动捕获异常,然后包装为RuntimeException抛出
使用roobackFor属性指定需要捕获的异常
3.内部异常被catch:内部异常被处理try catch处理,并没有抛出异常,异常捕获失败,事务控制不会回滚。
4.方法非public:Transactional注解标注方法修饰符为非public时,@Transactional注解将会不起作用。因为@Transactional 的工作原理是基于AOP来实现的,所以,必须作用在public的方法上才行
5.同一个类中方法调用,导致@Transactional失效:其实这还是由于使用Spring AOP代理造成的,因为只有当事务方法被当前类以外的代码调用时,才会由Spring生成的代理对象来管理
开发中避免不了会对同一个类里面的方法调用,比如有一个类Test,它的一个方法A,A再调用本类的方法B(不论方法B是用public还是private修饰),但方法A没有声明注解事务,而B方法有。则外部调用方法A之后,方法B的事务是不会起作用的。这也是经常犯错误的一个地方
6.数据库不支持事务:如mysql的数据库引擎,innodb支持事务,而myisam就不支持。
7.新开启一个线程:spring实现事务的原理是通过ThreadLocal把数据库连接绑定到当前线程中,新开启一个线程获取到的连接就不是同一个了。