Spring 事务回滚,AOP拦截做切换数据源失败问题解决

本文探讨了在Spring框架中,AOP与事务管理先后顺序不当导致的数据源切换失败问题。通过调整AOP切面与事务管理的优先级,确保事务回滚在@AfterThrowing注解处理之前完成,避免数据源连接池被锁。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

问题描述:方法出错,导致事务回滚,然后AOP中使用@AfterThrowing注解来做方法出错后的处理,处理方式为将错误信息存入另一个数据库的表中。运行后报错,
错误信息一般为:Error updating database.Cause: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException:Table 'test.logs' doesn't exist ,数据库表找不到,这是由于数据源没切换成功。

问题原因:

Spring中的事务是通过AOP来实现的,所以当我们自己写AOP拦截的时候,就会碰到事务和自定义AOP执行的先后顺序问题,如本文的动态切换数据源的问题。

这里我们使用Spring Order来定义AOP先后顺序,顺带稍微讲一下这个Spring Order。这里借用Ordered接口里的一句话Higher values are interpreted as lower priority。也就是值越高,优先级越低。反过来就是值越低,优先级越高。
但是这里有个问题,上句话说的越高越低和越低越高指的是在执行方法的前的AOP操作,AOP拦截是按照这个顺序,在执行方法后的AOP操作,反之顺序

还有就是Spring数据源真正切换的关键是AbstractRoutingDataSource的determineTargetDataSource() 方法,此方法是在建立数据库连接时触发。
而事务是在connection层面管理的,启用事务后,一个事务内部的connection是复用的,所以就算AOP切了数据源字符串,但是数据源并不会被真正修改。

因为事务回滚和本文的@AfterThrowing都是在执行方法后,而且事务回滚顺序要在@AfterThrowing前面完成,否则数据源连接池会被事务锁住。按照上面的分析,这个事务回滚的Order值要大于这个自定义AOP中Order的值。

解决方案:

1、Aop切面类实现Ordered接口,实现getOrder()方法,如下

@Aspect
@Component
public class LogsAspect implements Ordered{
	
	@Override
	public int getOrder() {
		// TODO Auto-generated method stub
		return 1;
	}
}

2、xml事务管理配置 order大于上面配置的1 或者不配置

<tx:annotation-driven transaction-manager="transactionManager" order="2" />

配置完上面两个步骤后,问题也就解决了。

讲到这里,本篇文章到此也就结束了,如果文章中有问题,或者有一些不够严谨完善的地方,希望大家体谅体谅。欢迎大家留言,交流交流。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值