专栏首页开发技术Spring 下,关于动态数据源的事务问题的探讨

Spring 下,关于动态数据源的事务问题的探讨

开心一刻

  毒蛇和蟒蛇在讨论谁的捕猎方式最高效。

  毒蛇:我只需要咬对方一口,一段时间内它就会逐渐丧失行动能力,最后死亡。

  蟒蛇冷笑:那还得等生效时间,我只需要缠住对方,就能立刻致它于死地。

  毒蛇大怒:你缠它身子,你下贱!

  蟒蛇:你不也亲了它吗?

前情回顾

看着文章的标题,不知道大家能否想到具体是什么问题,如果你有点懵,那就对了! (你不懵的话我这篇文章就没存在的意义了,嘿嘿)

在给大家指出具体是什么问题时,我们先来回顾一些内容

  Spring 事务原理

  相信大家对这个都能说上来一些,Spring 事务是 Spring AOP 的一种具体应用,底层依赖的是动态代理

  大致流程类似如下

  通过代理对象来调用目标对象,而在代理对象中有事务相关的增强处理

  具体细节可参考以下文章      

Spring 事务源码解析

结合 ThreadLocal 来看 Spring 事务源码,感受下清泉般的洗涤!

记一次线上问题 → 事务去哪了

  Spring 动态数据源原理

原理解密 → Spring AOP 实现动态数据源(读写分离),底层原理是什么中已经详细介绍过了,流程大体如下

  Spring AOP → 将我们指定的 lookupKey 放入 ThreadLocal

  ThreadLocal → 线程内共享 lookupKey

  DynamicDataSource → 对多数据源进行封装,根据 ThreadLocal 中的 lookupKey 动态选择具体的数据源

有什么问题

既然事务和动态数据源都是 Spring AOP 的具体应用,那么代理就存在先后顺序了

要么是

要么是

我们来看看这两者有什么区别

  事务在前,动态数据源在后

  此时,事务的前置增强处理会先生效,那么此时开始事务获取的 Connection 从哪来 ? 肯定是从 DynamicDataSource 来,因为我们给事务管理器配置的就是它

    @Bean
    public PlatformTransactionManager transactionManager(@Qualifier("dynamicDataSource") DataSource dynamicDataSource) {
        // 配置事务管理, 使用事务时在方法头部添加@Transactional注解即可
        return new DataSourceTransactionManager(dynamicDataSource);
    }

  既然是从 DynamicDataSource 获取的 Connection,那 DynamicDataSource 根据 lookupKey 获取 Connection 的时候,会从 masterDataSource 数据源获取还是从 slaveDataSource 数据源获取 ?因为此时还未将 lookupKey 绑定到当前线程,那么 DynamicDataSource 会从默认数据源获取,而我们配置的默认数据源是 slaveDataSource

    /**
     * 获取当前线程的数据源
     * @return
     */
    public static DataSourceType getDataSourceType()
    {
        return  HOLDER.get() == null ? DataSourceType.SLAVE : HOLDER.get();
    }

  说白了,此时的动态数据源对事务不生效,事务始终从默认数据源获取 Connection,而没有动态的效果,这就是问题了

  Talk is cheap. Show me the code,我们来看看是不是真的如上所说

192.168.0.112 正是我们的从库,对应的就是我们的默认数据源 slaveDataSource 

  动态数据源在前,事务在后

  此时,动态数据源的前置增强会先执行,DynamicDataSource 需要的 lookupKey 会先于事务绑定到当前线程,那么事务从 DynamicDataSource 获取 Connection 的时候就能根据当前线程的 lookupKey 来动态选择 masterDataSource 还是 slaveDataSource

  此种情况是没有问题的

解决问题

总结下问题:如何保证事务中的动态数据源也有动态的效果,也就是如何保证动态数据源的前置增强先于事务

我们知道 Spring AOP 是能够指定顺序的,只要我们显示的指定动态数据源的 AOP 先于 事务的 AOP 即可;如何指定顺序,常用的方式是实现 Order 接口,或者使用 @Order 注解,Order 的值越小,越先执行,所以我们只需要保证动态数据源的 Order 值小于事务的 Order 值即可

我们先来看看事务的 Order 值默认是多少,在 EnableTransactionManagement 注解中

    /**
     * Indicate the ordering of the execution of the transaction advisor
     * when multiple advices are applied at a specific joinpoint.
     * <p>The default is {@link Ordered#LOWEST_PRECEDENCE}.
     */
    int order() default Ordered.LOWEST_PRECEDENCE;

默认是最低级别(值非常大),那么我们只需要保证动态数据源的 Order 比这个值小就好,我们就取 1

  @Component
  @Slf4j
  @Order(1)
  public class DynamicDataSourceAspect {

我们在来看看是否真的可行

已经不是默认的 slaveDataSource ,而是我们指定的 masterDataSource(通过 @MasterSlave(MASTER) 指定)

至此,相信大家已经弄清楚了有什么问题,以及如何解决它

什么,还没理解 ? 你过来,我保证不打死你

总结

1、不只是动态数据源和事务,只要涉及到多个 AOP,就可能会有顺序问题,这是值得大家注意的

2、相关约束

  主数据库执行 INSERT UPDATE DELETE 操作,可能还有部分 SELECT 操作(主从同步多少有延时)

  从数据库只执行 SELECT 操作

  默认数据源最好设置成主数据源,防止粗心将更新操作执行到了从数据库;楼主之所以设置成从数据源,是考虑到绝大多数数据库操作是查询,这样可以减少代码量;具体怎么选,需要大家结合实际情况来决定

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Spring 下,关于动态数据源的事务问题的探讨

    看着文章的标题,不知道大家能否想到具体是什么问题,如果你有点懵,那就对了!(你不懵的话我这篇文章就没存在的意义了,嘿嘿)

    好好学java
  • 为什么要有Spring AOP?

    上一篇从Web开发演进过程的一个侧面简述了一下为什么会有Spring?事实上只介绍了为什么会有Spring IOC(控制反转/依赖注入)以及Spring IOC...

    Java后端技术
  • 为什么要有Spring AOP?

    上一篇从Web开发演进过程的一个侧面简述了一下为什么会有Spring?事实上只介绍了为什么会有Spring IOC(控制反转/依赖注入)以及Spring IOC...

    企鹅号小编
  • 为什么你要用 Spring?

    现代 Spring 几乎成为了 Java 在企业级复杂应用开发的代名词,得益于 Spring 轻量简单的设计哲学和其开放包容的生态圈,确实为廉颇老矣,尚能饭否的...

    phoenix.xiao
  • 书单丨构建响应式微服务架构——5本书了解微服务最新动向

    《Spring响应式微服务:Spring Boot 2+Spring 5+Spring Cloud实战》

    博文视点Broadview
  • 《Spring设计思想-事务篇》1.数据库连接和Java线程的关系

    版权声明:本文为博主原创文章,未经博主允许不得转载。 https://louluan.blog.csdn.net/article/detail...

    亦山
  • 深入剖析-mybatis-整合Spring原理(三)

    在前两篇文章我们在 mybatis 源码中探究了他的运行原理,但在实际使用中,我们需要将其和Spring整合使用,特别是当下流行的SpringBoot,那么,m...

    用户5224393
  • 硬核图书系列:《Spring Boot编程思想(核心篇)》

    小编说: 疫情像施了魔法一样,改变了我们每个人春节的轨迹。时间则从永远不够用突然变成了多得似乎不知干什么用。博文菌希望疫情没有改变我们那颗求知若渴的心。

    博文视点Broadview
  • 不忘初心,砥砺前行|暨 InfoQ 写作平台一周年

    与 InfoQ 相识的时间不算短了,2017 年 10 月 22 日加入,但 2020 年 9 月才在平台上发布第一篇文章,11 月后才开始连载。

    程序员架构进阶
  • 小白和进阶都适用! java学习路上必看的书单

    男怕入错行,女怕嫁错郎,学java最怕看错书!也是很久之前就想写这篇了,以前也零零星星的推荐过几本书,但是始终没有这样认真的整理一篇出来,这篇文章就是和...

    微笑的小小刀
  • Spring Cloud Kubernetes动态配置实现原理与源码分析

    Spring为Spring Cloud在Bean的生命周期、Bean的BeanPostProcessor以及AOP层面提供实现动态刷新配置的支持,而Spring...

    Java艺术
  • (三)spring cloud微服务分布式云架构 - Spring Cloud集成项目简介

    Spring Cloud集成项目有很多,下面我们列举一下和Spring Cloud相关的优秀项目,我们的企业架构中用到了很多的优秀项目,说白了,也是站在巨人的肩...

    用户7788846
  • SpringBoot+Mybatis配置多数据源及事务方案

    可能由于业务上的某些需求,我们的系统中有时往往要连接多个数据库,这就产生了多数据源问题。

    猿天地
  • 码云周刊 | 面试之前,或许该高效率地学点干货!

    一周热门资讯回顾 1、程序员多大年纪算高龄,届时该何去何从? ? 随着年龄的增长,程序员会相对难以保持技能更新。许多人宁愿留在自己的舒适区,不冒任何风险。即使...

    码云Gitee
  • 为什么选择 Spring 作为 Java 框架?

    在本文中,我们将讨论 Spring 作为最流行的 Java 框架之一的主要价值体现。

    乱敲代码
  • 为什么选择 Spring 作为 Java 框架?

    在本文中,我们将讨论 Spring 作为最流行的 Java 框架之一的主要价值体现。

    JAVA葵花宝典
  • 为什么选择 Spring 作为 Java 框架?

    在本文中,我们将讨论 Spring 作为最流行的 Java 框架之一的主要价值体现。

    Java技术江湖
  • Java项目框架搭建系列(Java学习路线)-博客提纲

    你会根据一个现有项目A复制一下搭建出另外一个类似框架的项目B,然后在项目B上进行业务逻辑开发。

    全栈程序员站长
  • 微服务框架和工具大全

    在《Java微服务》一书中,我们使用 Spring Cloud,它提供使微服务非常容易地开发所需的所有工具和平台。Spring Cloud使用 Netflix开...

    博文视点Broadview

扫码关注云+社区

领取腾讯云代金券