AbstractRoutingDataSource数据源动态切换、跨库事物失效问题解决方案

完整代码:GitHub - duanbin0414/dynamic-datasource-boot: 数据源动态切换事务支持

数据源动态切换、跨库事物失效问题解决方案

一、问题出现的场景

系统架构设计、每个企业一个企业库、通过数据源切在平台库、和企业库之间动态切换完成业务操作。

二、跨库事物失效的原因

1、Spring@Transactional不支持跨数据源事物,Spring 事物控制是基于数据库链接进行的,当数据源切换后,数据库链接切换,事物回滚只能回退,当前持有的链接。
2、Spring开启事物后,会将当前数据库及数据库链接资源进行线程绑定,导致数据源切换失效(数据源切换执行后,并未获取到新的数据库链接)。

三、解决方案

基于InheritableThreadLocal + aop 针对添加了跨库事务注解的方法进行拦截、线程标记、覆写mybatis自动提交,通过aop手动提交/回退,实现跨库事务。

1、自定义跨库事物注解

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface MultiTransactional {
}

2、对有标记的请求、保存数据库链接、关闭自动提交

在这里插入图片描述
在动态数据源获取数据库链接处特殊处理,如果开启了跨库事物,则返回包装后对connection对象(包装主要为了避免mybatis自动提交和回滚)、并且将对应的数据库链接保存到线程上下文。

3、对开启了跨库事物方法进行拦截、标记、提交/回滚

基于InheritableThreadLocal 对添加了跨库事物注解@MultiTransactional的方法进行拦截
1)在方法执行前:设置multilTransactionalStatus = true;
2)在方法执行异常时:从当前线程上线文获取到所有链接、统一rollback();
3)在方法正常执行结束:从当前线程上线文获取到所有链接、统一commit();
在这里插入图片描述

四、注意事项

1、使用InheritableThreadLocal(带继承)能保证线程标记不丢失。
2、需要对执行手动事物的链接对象包装、覆写submit()、rollback()方法、否则mybatis在sql执行后会自动提交,导致事物失败。
3、请求执行结束后(包含正常、异常情况)均要提交/回滚事物、释放资源,避免内存泄漏、链接异常。
4、本文使用了ThreadLoca保存链接,同理也可使用HttpServletRequest对象保存链接资源(会在定时任务等特殊场景下失效),可酌情考虑使用。

五、压测报告

对同一段代码进行三种事务控制: 不添加事务、添加@Transactional、添加@MultiTransactional 进行压测对比。
在这里插入图片描述
无事务控制
在这里插入图片描述
添加Transactional
在这里插入图片描述
添加MultiTransactional
在这里插入图片描述在这里插入图片描述无事务控制
在这里插入图片描述添加Transactional
在这里插入图片描述
添加MultiTransactional
在这里插入图片描述在这里插入图片描述
无事务控制
在这里插入图片描述添加Transactional
在这里插入图片描述
添加MultiTransactional
在这里插入图片描述
注:所有异常情况均为 429 Too Many Requests (太多请求)

结论:解决方案性能ok

经过三种事务控制压测结果对比,MultiTransactional注解方式支持跨库事务、没有带来额外的性能压力。

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值