同一个Service类中非事务方法 调用 事务方法,事务失效 解决方法
在平时开发中,同一个Service类中非事务方法调用事务方法,事务会失效,这里简单解释一下原因:
spring采用动态代理机制来实现事务控制,而动态代理最终都是要调用原始对象的,而原始对象在去调用方法时,是不会再触发代理了!可以理解为同一个类中非事务方法调用方法时用的是当前对象去调用,而不是spring生成的代理对象,所以会导致事务失效。
问题场景:
controller调用方法A,方法A调用 方法B1、方法B2、、、,,(方法A、B1、B2、、在同一个service中),,,在执行的过程中,,,希望的是方法B1、B2、B3里面,抛异常了就回滚,不抛异常就正常运行,,,而最外层的方法A是正常运行的
A方法:
B1 、B2方法
调用结果:
解决方法:
方法1.将需要进行事务管理的方法单独写到一个Service文件中
@Servcie
public class ServiceA {
@Autowired
private ServiceB serviceB;
public void save(User user) {
queryData1();
queryData2();
//调用事务方法
serviceB.doSave(user);
}
}
-------------------------分界线----------------------------------------
//新加的 @Servcie
@Servcie
public class ServiceB {
//事务方法
@Transactional(rollbackFor=Exception.class)
public void doSave(User user) {
addData1();
updateData2();
}
}
方法2.在该Service类中注入自己,使用注入的自己进行调用事务方法
@Servcie
public class ServiceA {
//注入自己
@Autowired
private ServiceA serviceA;
public void save(User user) {
queryData1();
queryData2();
//this.doSave(user);
//使用注入的自己 调用事务方法
serviceA.doSave(user);
}
@Transactional(rollbackFor=Exception.class)
public void doSave(User user) {
addData1();
updateData2();
}
}
可能有些人可能会有这样的疑问:这种做法会不会出现循环依赖问题?
其实spring ioc内部的三级缓存保证了它,不会出现循环依赖问题
方法3.使用 AopContext.currentProxy() 获取代理对象
(1)增加maven依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
(2)springboot启动类加上注解:@EnableAspectJAutoProxy(exposeProxy = true)
(3)Service类中,获取代理对象后,再去调用事务方法
CommServiceImpl currentProxy = (CommServiceImpl) AopContext.currentProxy()
相关知识点:
@Transactional修饰的方法的特点: public方法,且事务内尽可能简单:
Spring事务是通过AOPQ实施事务增强的。由于接口的方法是public的,这句要求实现类的实现方法必须是public 的 (不能是protect,private等),同时不能使用static的修饰符。即只有public的方法才可以被aop增强。
处理过程尽量的简单。尤其是带锁的事务方法,能不放在事务里面的最好不要放在事务里面。可以将常规的数据库查询操作放在事务前面进行,而事务内进行增、删、改、加锁查询等操作。
@事务中代码异常抛出之后导致事务并无回滚的几种情况:
1.@事务性应用在非公开修饰的方法上。
2.同一个类中方法调用,导致@Transactional失效。比如有一个类Test,它的一个方法A,A再调用本类的方法B (不论方法B是用public还是private修饰),但方法A没有声明注解事务,而B方法有。则外部调用方法A之后,方法B的事务是不会起作用的
3.异常被你的catch吃掉 导致@事务性失效
4…