我最初的想法是: 读方法走读库,写方法走写库(一般是主库),保证在Spring提交事务之前确定数据源.

保证在Spring提交事务之前确定数据源,这个简单,利用AOP写个切换数据源的切面,让他的优先级高于Spring事务切面的优先级。至于读,写方法的区分可以用2个注解。

但是如何切换数据库呢? 我完全不知道!多年经验告诉我

我搜索了一些网文,发现都提到了一个AbstractRoutingDataSource类。查看源码注释如下

/**

Abstract {@link javax.sql.DataSource} implementation that routes {@link #getConnection()}

* calls to one of various target DataSources based on a lookup key. The latter is usually

* (but not necessarily) determined through some thread-bound transaction context.

*

* @author Juergen Hoeller

* @since 2.0.1

* @see #setTargetDataSources

* @see #setDefaultTargetDataSource

* @see #determineCurrentLookupKey()

*/

AbstractRoutingDataSource就是DataSource的抽象,基于lookup key的方式在多个数据库中进行切换。重点关注setTargetDataSources,setDefaultTargetDataSource,determineCurrentLookupKey三个方法。那么AbstractRoutingDataSource就是Spring读写分离的关键了。

仔细阅读了三个方法,基本上跟方法名的意思一致。setTargetDataSources设置备选的数据源集合。 setDefaultTargetDataSource设置默认数据源,determineCurrentLookupKey决定当前数据源的对应的key。

但是我很好奇这3个方法都没有包含切换数据库的逻辑啊!我仔细阅读源码发现一个方法,determineTargetDataSource方法,其实它才是获取数据源的实现。源码如下:

简单说就是,根据determineCurrentLookupKey获取的key,在resolvedDataSources这个Map中查找对应的datasource!,注意determineTargetDataSource方法竟然不使用的targetDataSources!

那一定存在resolvedDataSources与targetDataSources的对应关系。我接着翻阅代码,发现一个afterPropertiesSet方法(Spring源码中InitializingBean接口中的方法),这个方法将targetDataSources的值赋予了resolvedDataSources。源码如下:

afterPropertiesSet 方法,熟悉Spring的都知道,它在bean实例已经创建好,且属性值和依赖的其他bean实例都已经注入以后执行。

也就是说调用,targetDataSources,defaultTargetDataSource的赋值一定要在afterPropertiesSet前边执行。

AbstractRoutingDataSource简单总结:

  1. AbstractRoutingDataSource,内部有一个Map<Object,DataSource>的域resolvedDataSources

  2. determineTargetDataSource方法通过determineCurrentLookupKey方法获得key,进而从map中取得对应的DataSource。

  3. setTargetDataSources 设置 targetDataSources

  4. setDefaultTargetDataSource 设置 defaultTargetDataSource,

  5. targetDataSources和defaultTargetDataSource 在afterPropertiesSet分别转换为resolvedDataSources和resolvedDefaultDataSource。

  6. targetDataSources,defaultTargetDataSource的赋值一定要在afterPropertiesSet前边执行。

进一步了解理论后,读写分离的方式则基本上出现在眼前了。(“下列方法不唯一”)

先写一个类继承AbstractRoutingDataSource,实现determineCurrentLookupKey方法,和afterPropertiesSet方法。afterPropertiesSet方法中调用setDefaultTargetDataSource和setTargetDataSources方法之后调用super.afterPropertiesSet。

之后定义一个切面在事务切面之前执行,确定真实数据源对应的key。但是这又出现了一个问题,如何线程安全的情况下传递每个线程独立的key呢?没错使用ThreadLocal传递真实数据源对应的key。

ThreadLocal,Thread的局部变量,确保每一个线程都维护变量的一个副本

到这里基本逻辑就想通了,之后就是写了。

DataSourceContextHolder 使用ThreadLocal存储真实数据源对应的key

DataSourceAopAspect 切面切换真实数据源对应的key,并设置优先级保证高于事务切面

RoutingDataSouceImpl实现AbstractRoutingDataSource的逻辑

基本逻辑实现完毕了就进行,通用设置,设置数据源,事务,SqlSessionFactory等

其他代码,就不在这里赘述了,有兴趣可以移步完整代码。

使用Spring写读写分离,其核心就是AbstractRoutingDataSource,源码不难,读懂之后,写个读写分离就简单了!。

AbstractRoutingDataSource重点回顾:

  1. AbstractRoutingDataSource,内部有一个Map<Object,DataSource>的域resolvedDataSources

  2. determineTargetDataSource方法通过determineCurrentLookupKey方法获得key,进而从map中取得对应的DataSource。

  3. setTargetDataSources 设置 targetDataSources

  4. setDefaultTargetDataSource 设置 defaultTargetDataSource,

  5. targetDataSources和defaultTargetDataSource 在afterPropertiesSet分别转换为resolvedDataSources和resolvedDefaultDataSource。

  6. targetDataSources,defaultTargetDataSource的赋值一定要在afterPropertiesSet前边执行。

这周确实有点忙,周五花费了些时间不过总算实现了自己的诺言。

完成承诺不容易,喜欢您就点个赞!

springboot读写分离--temp的更多相关文章

  1. 搭建 springboot 2.0 mybatis 读写分离 配置区分不同环境

    最近公司打算使用springboot2.0, springboot支持HTTP/2,所以提前先搭建一下环境.网上很多都在springboot1.5实现的,所以还是有些差异的.接下来咱们一块看一下. 文 ...

  2. SpringBoot使用Sharding-JDBC读写分离

    本文介绍SpringBoot使用当当Sharding-JDBC进行读写分离. 1.有关Sharding-JDBC 本文还是基于当当网Sharding-Jdbc的依赖,与上一篇使用Sharding-Jd ...

  3. SpringBoot+MyBatis+MySQL读写分离

    1.  引言 读写分离要做的事情就是对于一条SQL该选择哪个数据库去执行,至于谁来做选择数据库这件事儿,无非两个,要么中间件帮我们做,要么程序自己做.因此,一般来讲,读写分离有两种实现方式.第一种是依 ...

  4. SpringBoot数据库读写分离之基于Docker构建主从数据库同步实例

    看了好久的SpringBoot结合MyBatista实现读写,但是一直没有勇气实现他,今天终于接触到了读写分离的东西,读写分离就是讲读操作执行在Slave数据库(从数据库),写操作在Master数据库 ...

  5. SpringBoot+MyBatis+MySQL读写分离(实例)

    ​ 1. 引言 读写分离要做的事情就是对于一条SQL该选择哪个数据库去执行,至于谁来做选择数据库这件事儿,无非两个,要么中间件帮我们做,要么程序自己做.因此,一般来讲,读写分离有两种实现方式.第一种是 ...

  6. Springboot + Mysql8实现读写分离

    在实际的生产环境中,为了确保数据库的稳定性,我们一般会给数据库配置双机热备机制,这样在master数据库崩溃后,slave数据库可以立即切换成主数据库,通过主从复制的方式将数据从主库同步至从库,在业务 ...

  7. 分库分表(6)--- SpringBoot+ShardingSphere实现分表+ 读写分离

    分库分表(6)--- ShardingSphere实现分表+ 读写分离 有关分库分表前面写了五篇博客: 1.分库分表(1) --- 理论 2.分库分表(2) --- ShardingSphere(理论 ...

  8. 分库分表(7)--- SpringBoot+ShardingSphere实现分库分表 + 读写分离

    分库分表(7)--- ShardingSphere实现分库分表+读写分离 有关分库分表前面写了六篇博客: 1.分库分表(1) --- 理论 2.分库分表(2) --- ShardingSphere(理 ...

  9. 读写分离很难吗?springboot结合aop简单就实现了

    目录 前言 环境部署 开始项目 注意 參考: 前言 入职新公司到现在也有一个月了,完成了手头的工作,前几天终于有时间研究下公司旧项目的代码.在研究代码的过程中,发现项目里用到了Spring Aop来实 ...

随机推荐

  1. ueditor整合之后前段不显示高亮

    自己整合ueditor插件后,发现在前段显示的时候并没有高亮处理 在网上看了一些方法后,自己尝试了下. 1.在页面上引入相关的js和css文件 主要是以下两个文件 <script src=&qu ...

  2. crontab 实际的应用

    每二天执行一次: 0 0 */2 * * command #注意分,时不能为星*,否则每分钟执行 每天零晨01,03执行: 0 01,03 * * * command 每2小时执行一次 0 */2 * ...

  3. android 获得SDCard信息

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools=&q ...

  4. MVC Html.AntiForgeryToken() 防止CSRF攻击 - CSDN博客

    原文:MVC Html.AntiForgeryToken() 防止CSRF攻击 - CSDN博客 (一)MVC Html.AntiForgeryToken() 防止CSRF攻击 MVC中的Html.A ...

  5. Javascript:如何调用全局变量?

    怎样使用全局变量呢? window.globalVariableName 参考: https://blog.csdn.net/zyz511919766/article/details/7276089

  6. 第二讲_图像数据处理Image Data Processing

    第二讲_图像数据处理Image Data Processing 深度模型出现后被弱化,但是思想的影子在深度模型中可以看到的 图片存储原理 RGB颜色空间:三通道(b,g,r),加法混色 CMY(K): ...

  7. 2017年记录CS+CV

    2017年3月开学,始终感觉自己计算机基础薄弱,加上之前自己也开始对机器学习,深度学习有一些了解,始终感觉没有入门.自己开始规划系统学习计算机软件(CS)和计算机视觉(CV)的基础知识.@2017/9 ...

  8. 转:CEO, CFO, CIO, CTO, CSO是什么

    转自:https://club.1688.com/threadview/26957122.html CEO, CFO, CIO, CTO, CSO是什么?(现在O太多了) 帖子创建时间:  2009年 ...

  9. 吃我一记咸鱼突刺——使用板载RTC定时开机

    前言 原创文章,转载引用务必注明链接.水平有限,欢迎指正. 2016年3月30日 Lemuntu(Base On Jessie) 3.10.37 原载于Lemaker论坛.汇总于此. 看ATC2603 ...

  10. mysql 复制数据库

    为了方便快速复制一个数据库,可以用以下命令 将db1数据库的数据以及表结构复制到newdb数据库 创建新的数据库 #mysql -u root -p123456 mysql>CREATE DAT ...