开心一刻

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

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

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

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

  蟒蛇:你不也亲了它吗?

前情回顾

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

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

  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 操作

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

Spring 下,关于动态数据源的事务问题的探讨的更多相关文章

  1. Spring Boot2.x 动态数据源配置

    原文链接: Spring Boot2.x 动态数据源配置 基于 Spring Boot 2.x.Spring Data JPA.druid.mysql 的动态数据源配置Demo,适合用于数据库的读写分 ...

  2. 如何通过Spring Boot配置动态数据源访问多个数据库

    之前写过一篇博客<Spring+Mybatis+Mysql搭建分布式数据库访问框架>描述如何通过Spring+Mybatis配置动态数据源访问多个数据库.但是之前的方案有一些限制(原博客中 ...

  3. Spring(AbstractRoutingDataSource)实现动态数据源切换--转载

    原始出处:http://linhongyu.blog.51cto.com/6373370/1615895 一.前言 近期一项目A需实现数据同步到另一项目B数据库中,在不改变B项目的情况下,只好选择项目 ...

  4. Spring(AbstractRoutingDataSource)实现动态数据源切换

    转自: http://blog.51cto.com/linhongyu/1615895 一.前言 近期一项目A需实现数据同步到另一项目B数据库中,在不改变B项目的情况下,只好选择项目A中切换数据源,直 ...

  5. spring AbstractRoutingDataSource实现动态数据源切换

    使用Spring 提供的 AbstractRoutingDataSource 实现 创建 AbstractRoutingDataSource 实现类,负责保存所有数据源与切换数据源策略:public ...

  6. 原理解密 → Spring AOP 实现动态数据源(读写分离),底层原理是什么

    开心一刻 女孩睡醒玩手机,收到男孩发来一条信息:我要去跟我喜欢的人表白了! 女孩的心猛的一痛,回了条信息:去吧,祝你好运! 男孩回了句:但是我没有勇气说不来,怕被打! 女孩:没事的,我相信你!此时女孩 ...

  7. Spring配置,JDBC数据源及事务

    <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.sp ...

  8. 【spring boot】SpringBoot初学(7)– 多数据源及其事务

    前言 github: https://github.com/vergilyn/SpringBootDemo 代码位置: 参考: Spring Boot Reference Guide , §77.2 ...

  9. Spring 实现动态数据源切换--转载 (AbstractRoutingDataSource)的使用

    [参考]Spring(AbstractRoutingDataSource)实现动态数据源切换--转载 [参考] 利用Spring的AbstractRoutingDataSource解决多数据源的问题 ...

随机推荐

  1. 【转】不怕难之BlockingQueue及其实现

    1. 前言 BlockingQueue即阻塞队列,它是基于ReentrantLock,依据它的基本原理,我们可以实现Web中的长连接聊天功能,当然其最常用的还是用于实现生产者与消费者模式,大致如下图所 ...

  2. CVE-2019-17564:Apache Dubbo反序列化漏洞复现

    0x00 漏洞背景 ①iiDubbo是一款高性能.轻量1级的开源java Rpc分布式服务框架. ②核心功能: ◉ 面向接口的远程过程调用 ◉ 集群容错和负载均衡 ◉ 服务自动注册与发现 ③特点: ◉ ...

  3. MySQL数据库02

    MySQL数据库 前言: 前面我们了解了什么是数据库,什么是MySQL数据库以及如何运用,接下来我们接着深入学习MySQL. (提前声明,以下所提供的事例不标准,仅供参考) 数据库的备份与还原: 备份 ...

  4. 【Code Force】Round #589 (Div. 2) D、Complete Tripartite

    题目链接 大致题意 把一个图分成三块,要求任意两块之间是完全图,块内部没有连线 分析 首先根据块内没有连线可以直接分成两块 假定点1是属于块1的,那么所有与点1连接的点,都不属于块1:反之则是块1的 ...

  5. 曹工说Spring Boot源码(26)-- 学习字节码也太难了,实在不能忍受了,写了个小小的字节码执行引擎

    曹工说Spring Boot源码(26)-- 学习字节码也太难了,实在不能忍受了,写了个小小的字节码执行引擎 写在前面的话 相关背景及资源: 曹工说Spring Boot源码(1)-- Bean De ...

  6. MATLAB中mean的用法

    https://blog.csdn.net/wangyang20170901/article/details/78745587 MATLAB中mean的用法 转载仙女阳 最后发布于2017-12-07 ...

  7. 使用PyTorch进行迁移学习

    概述 迁移学习可以改变你建立机器学习和深度学习模型的方式 了解如何使用PyTorch进行迁移学习,以及如何将其与使用预训练的模型联系起来 我们将使用真实世界的数据集,并比较使用卷积神经网络(CNNs) ...

  8. MATLAB 随机过程基本理论

    一.平稳随机过程 1.严平稳随机过程 clc clear n=0:1000; x=randn(1,1001); subplot(211),plot(n,x); xlabel('n');ylabel(' ...

  9. java中eclipse的安装和JDK的环境变量的配置以及记事本的使用

    2020-04-09 23:26:15 学习java的第一步当然就是环境配置了,java中的配置作为小白刚刚开始肯定会有点一点晕头转向的,开没等开始入门呢!就要准备放弃了.哈哈哈哈,没关系的,都是这么 ...

  10. 使用onclick/表单submit跳转到其他页面

    使用onclick 如果是本页显示可以直接用location,方法如下: - onclick="javascript:window.location.href='URL'" - o ...