简书日更 第10篇: Spring事务失效问题及解决方法
我们常用的是spring声明式事务,即使用@Transactional注解 来对需要事务的方法进行标注,在一定的情景下,会出现事务失效的问题,
这也是一个经常被问到的面试题,今天来解析一下。
若只想看 Spring事务失效问题的解决方法 请跳过前面2个小主题
1.Spring支持两种类型的事务管理
编程式事务管理:我们需要手动的对事务进行提交和回滚,需要一定的代码量和复杂度。
声明式事务管理:业务代码和事务管理分离,你只需用注解和XML配置来管理事务(SpringBoot中只需要使用注解即可)。
2.Spring事务的实现方式和实现原理
Spring事务的本质其实就是数据库对事务的支持,没有数据库的事务支持,spring是无法提供事务功能的。
真正的数据库层的事务提交和回滚是通过binlog或者redo log实现的。
3.Spring事务失效的几种可能
3.1 Spring因 传播行为失效
spring是可能会因为传播行为而失效的,当我们在RUD的时候,可能会对其中的多个方法进行事务,但对事务的传播行为限制有所不同,
又因为spring的声明式事务是基于AOP的,当不同的方法在同一个类中的时候,如果直接调用,则无法让AOP生效,则会导致被调用的方法
传播行为失效。
解决办法为:使用注入的方式,调用其方法。
3.2 Spring因 rollbackFor 失效
@Transactional的写法
开始@Transactional如果只这样写,
那,当投掷一个此类RuntimeException子类实例的实例时。(Errors也一样-交替地-标识事务回滚。)从事务方法中抛出的已检查异常将不被标识进行事务回滚。
让checked例外也回滚:在整个方法前加上@Transactional(rollbackFor = Exception.class)
让unchecked例外不回滚:@Transactional(notRollbackFor = RunTimeException.class)
不需要事务管理的(只查询的)方法:@Transactional(传播=传播。NOT_SUPPORTED)
注意:如果异常被try {} catch {}扔掉,事务就不回滚了,如果想让事务回滚必须再往外抛try {} catch {throw Exception}。
注意:
Spring团队的建议是你在具体的类(或类的方法)上使用@Transactional注解,而不要使用在类所要实现的任何接口上。你当然可以在接口上使用@Transactional注解,但是这将只能因为注解是不能继承的,这意味着如果您正在使用基于类的代理时,那么事务的设置将不能被基于类的代理所识别,而且对象也将不会被事务代理所包装(将被确认为严重的)。因此,请接受Spring团队的建议和在具体的类上使用@Transactional注解。
@Transactional注解标识的方法,处理过程正确 的简单。尤其是带锁的事务方法,能不放在事务里面的最好不要放在事务里面。可以将常规的数据库查询操作放在事务前面进行,而事务内部进行增值,删除,改,加锁查询等操作。