背景:记一次Springboot事务不起作用问题排查
springboot项目中的Application启动类中添加@EnableTransactionManagement注解开启事务。
接下来在需要添加事务的方法上添加@Transaction注解开启事务。@Transaction注解生效有几个需要注意的地方:
1.spring事务的支持是对数据库事务的支持。所以想要使用spring开启事务,首先数据库的引擎必须是支持事务的。比如mysql的myisam引擎就不支持事务
2.@Transaction需要加载public类型的方法上。其他类型的方法不报错,但是事务也不会生效。
3.@Transaction最好制定回滚的错误类型。roll back for = "具体的错误类型"。
因为spring事务管理默认是只会处理unchecked的异常:也就是runtime异常及其子类和错误(error)
checked异常包括Exception下除了runtimeException以外的异常。spring默认不会处理这些异常。所以需要我们在使用的时候在
@Transaction(rollbackFor = Exception.class)来指定回滚的异常。同样,也可以指定某个异常不回滚。可以使用norollbackFor = 具体的异常。
4.因为spring是通过代理对象来回滚事务的。所以,如果在一个为开启事务的方法中,直接调用本类中其他有事务的方法时,事务会失效。例如:
public class Test {
public void A() {
System.out.println("====> methodA");
B();
}
@Transactional(rollbackFor = Exception.class)
public void B() {
System.out.println("====> methodB");
}
}
无事务的方法A直接调用自己的有事务的方法B,会导致事务失效。原因是spring的事务是通过代理类实现的,自己直接调用自己的方法就没有通过代理类,所以事务不会生效。解决办法有:
1.可以通过暴露代理类,然后再通过本类的代理类调用有事务的方法。用时要在springboot启动类上添加@EnableAspectJAutoProxy(exposeProxy = true)开启暴露代理类。
public class Test {
@Transactional(rollbackFor = Exception.class)
public void A() {
System.out.println("====> methodA");
((Test)AopContext.currentProxy()).B();
}
@Transactional(rollbackFor = Exception.class)
public void B() {
System.out.println("====> methodB");
}
}
2.可以再添加一层,将A,B方法分在不同的类里,这样也能达到开启事务的目的。
5、@Transactional(rollbackFor = Exception.class, transactionManager = "mysqlsumTransactionManager")
mysqlsumTransactionManager 是自定义的数据源名称(当你的应用为多数据源时), 自定义数据源及事务管理器 回滚要指定,否则回滚不生效,而且要加在方法上面,加载类上无法生效启动类也上开启事务。
6、aop切片 包裹事务导致事务不生效原因:
单数据源,手动配置datasource也不生效,问题不在于此。
添加异常controller adive处理异常的时候发现,异常信息没有被拦截处理,而是被service层aspect around拦截打出堆栈信息处理了,如图:
打出堆栈信息说明service层异常被捕获处理了,导致事务管理机制无法检测到事务。
尝试1:注释掉around aspect 事务生效,说明around拦截service处理了异常,导致事务没有回滚。 难道这里区分processJoinPoint 和JoinPoint的区别?
测试 切片的around 环绕通知换成before前置通知,事务生效,即将service层的around aspect 修改成before即可解决事务问题。
尝试2:切service日志around处理为什么不影响事务?
再次尝试修改service层around通知方法,发现catch异常后是reture exception 并不是throw exception
修改around通知中捕获处理异常后,不要return(return 异常信息被加工处理),直接抛出即可,事务生效。
现在重新来看一下spring事务机制,像回环加工厂一样,最先处理的最后响应。