Spring事务失效的原因和解决方案
大部分原因:
1.数据库不支持事务,Innodb支持事务,myIsam不支持事务
2.事务方法没有被spring管理,如果使用springboot的话需要加上注解@Component才生效
3.方法没有被public修饰
4.同一类中方法调用(this调用同一类中的方法)
5.没有配置事务管理器
6.方法的事务传播类型不支持事务
7.异常被吞掉了
解决方案:
1,2 , 3这三种情况自己在选用时避开即可
4.同一类中方法调用
如果同一个类中的两个方法分别为A和B,方法A上没有添加事务注解,方法B上添加了 @Transactional事务注解,方法A调用方法B,则方法B的事务会失效
@Service
public class MyService {
public void submitOrder(){
//保存操作
orderDao.saveOrder(order);
//更新操作
this.update(order);
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void update(Order order){
imapper.update(order);
}
}
原因是this
关键字调用方法时,实际上是直接调用了目标对象的方法,而绕过了代理对象,解决办法就是获取原始的代理对象,可以使用 Spring 的 AopContext.currentProxy()
方法获取当前代理对象,然后使用代理对象调用目标方法(aspectJ的方式)
步骤:
1.引入aspectJ的maven模块
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.6</version>
</dependency>
2.springboot的main方法加上注解@EnableAspectJAutoProxy(exposeProxy = true)开启AspectJ动态代理
@MapperScan("com.hmdp.mapper")
//开启AspectJ动态代理
@EnableAspectJAutoProxy(exposeProxy = true)
@SpringBootApplication
public class HmDianPingApplication {
public static void main(String[] args) {
SpringApplication.run(HmDianPingApplication.class, args);
}
}
然后使用AopContext.currentProxy()
@Service
public class MyService {
public void submitOrder(){
//保存操作
orderDao.saveOrder(order);
//更新操作
//this.update(order);
MyService proxy = (MyService)AopContext.currentProxy();
proxy.update(order);
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void update(Order order){
imapper.update(order);
}
}
7.异常处理
如果在事务中,手动try…catch…并且自己处理了异常,没有向外抛出runtimeException,就不会回滚。
Spring的事务传播机制
了解一下,如果配置错事务传播参数也会导致事务失效(如never)
Spring事务生效的是Required,Requires_new,Nested
- REQUIRED:如果当前没有事务,则创建一个新事务,如果已经存在一个事务中,加入到这个事务中。
- SUPPORTS:支持当前事务,如果当前没有事务,就以非事务方式执行。
- MANDATORY:使用当前的事务,如果当前没有事务,就抛出异常。
- REQUIRES_NEW:创建一个新的事务,如果当前存在事务,则把当前事务挂起。
- NOT_SUPPORTED:以非事务方式执行操作,如果当前存在事务,则把当前事务挂起。
- NEVER:以非事务方式执行,如果当前存在事务,则抛出异常。
- NESTED:如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则创建一个新事务。
required模式下,多个事务方法可以共享一个事务,只有最外层的事务方法会真正的提交事务,如果内层事务方法抛出异常,整个事务都会回滚。
nested模式下,多个事务方法之间形成了一个嵌套的事务结构,内层事务方法可以独立地提交或回滚事务,而不会影响外层事务方法。如果内层事务方法抛出异常,只会回滚该嵌套事务,而不会影响外层事务
requires_new模式下
创建一个新事务,如果当前存在事务,则把当前事务挂起,每个事务方法都有自己的事务,内层事务的回滚不会影响外层事务