springboot-AOP 切换多数据源时 @Transactional 导致切换数据源失败的问题--已解决

使用场景

项目有多个数据源, 根据配置文件配置的连接数来自动生成多数据源配置 并且使用 aop切换数据源,具体实现方式 网上有很多 使用的是 AbstractRoutingDataSource  重写 determineCurrentLookupKey 方法

默认数据源为ninja  第二个数据源为 test

今天要说的问题就是@Transactional  和切换数据源 @DS 同时使用时 切换数据源无效的问题

当我在一个service方法上切换了数据源时同时 加入了事务 ,此时方法中需要操作两次数据库 需要保证事务 下图:

然后在加了 @Transactional  注解后出现问题: 数据源一直都是使用的默认数据源  而非我指定的 test数据源, 然后各种查资料发现 在同一个事务中数据源是无法切换的  最终发现在我debug源码时,

1在切换数据源之前 @Transactional 先执行 切面,此时会去获取数据源,而此时数据源还没有切换 就会获取默认的数据源 源码:

2在执行完@Transactional  锁定数据源之后, @ds切面后执行, 此时切换数据源的时候只是改变了缓存数据源配置的key字符串,在执行db操作的时候没有重新根据当前字符串的key去获取最新的数据源,所以表现出 数据源未切换的现象,查询报错表名不存在

 

解决方法:

思考: 如果在事务获取数据源之前,切换数据源问题不就解决了吗, 查了资料发现 在自定义的切面中 加入

@Order(-1) 来执行方法上的注解的执行顺序,可以优先于@Transactional  执行

然后再次进行测试, 数据源成功切换,事务仍然有效,问题解决

注意:此事务内只能保证同一个数据源, 非分布式事务

 

 

  • 8
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 7
    评论
Spring Boot中,我们可以使用AOP(Aspect Oriented Programming)来实现在事务前切换数据源。 首先,我们需要定义两个数据源,例如DataSource1和DataSource2。然后,在应用程序中配置这些数据源,并使用@Transactional注解将需要使用不同数据源的方法标记为事务。 接下来,我们需要定义一个切面,使用@Aspect注解标记,来在事务前切换数据源。在切面中,我们可以使用@Before注解来指定在事务开始前执行的方法,并且在该方法中使用ThreadLocal来存储当前线程需要使用的数据源。 下面是一个示例代码: ```java @Aspect @Component public class DataSourceAspect { @Before("execution(* com.example.service.*.*(..)) && @annotation(transactional)") public void setDataSource(JoinPoint point, TargetDataSource transactional) { String dataSourceKey = transactional.value(); DataSourceContextHolder.setDataSource(dataSourceKey); } } ``` 在上面的代码中,@Before注解指定了要在Service层中所有被@Transactional注解标记的方法执行前切换数据源,并且@Transactional注解中的value属性用于指定要使用的数据源。在setDataSource方法中,我们使用DataSourceContextHolder类的setDataSource方法来将当前线程需要使用的数据源保存到ThreadLocal中。 最后,我们需要定义一个DataSourceContextHolder类来管理ThreadLocal对象,并在需要使用数据源从ThreadLocal中获取当前线程需要使用的数据源。下面是一个示例代码: ```java public class DataSourceContextHolder { private static final ThreadLocal<String> dataSourceKey = new ThreadLocal<>(); public static void setDataSource(String key) { dataSourceKey.set(key); } public static String getDataSource() { return dataSourceKey.get(); } public static void clearDataSource() { dataSourceKey.remove(); } } ``` 在上面的代码中,我们使用ThreadLocal来保存当前线程需要使用的数据源,并提供了方法来获取当前线程需要使用的数据源和清除ThreadLocal对象。当事务执行完毕后,我们需要清除ThreadLocal对象以释放资源。 这样,我们就可以通过AOP切换数据源了。当我们需要在事务中使用不同的数据源,只需要在@Transactional注解中指定要使用的数据源即可。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值