前言
上一章介绍了MySQL主从同步,实现了双击热备,这里给大家介绍一下通过代码去实现读写分离。
读写分离
什么事读写分离?为什么读写分离?等等问题,我就不去介绍了有大神已经整理分析很好了,大家可以看一下这篇文章(很短)对读写分离有个大致的理解
分析
我们介绍的就是读写分离的第一种方式:基于程序代码内部实现。项目框架为SSM框架的一个web项目,如何搭建看这篇文章,上一篇中从同步配置了两个数据库,我们将为每个库定义一个数据源,分别为master,slave,增删改、有事务的操作在主库master,查询在从库slave。
综上,需求就是:根据数据库操作的类型去动态的修改要执行的数据源。
需求搞清楚之后,自然将会有下面两个问题
1. 如何切换数据源
我们在spring-jdbc.jar下找到一个AbstractRoutingDataSource类
//此类是一个抽象类,省略其他代码,看咱们关心的两行代码
public abstract class AbstractRoutingDataSource extends AbstractDataSource implements InitializingBean {
//存放要动态切换的数据源
private Map<Object, Object> targetDataSources;
//每次操作数据库都会调用此方法,根据返回值动态选择数据源
//抽象方法,定义当前使用的数据源(返回值为动态数据源的key值)
protected abstract Object determineCurrentLookupKey();
}
由上面的类便知,我们只要把我们的数据源放到targetDataSources里,继承了AbstractRoutingDataSource 类,实现determineCurrentLookupKey方法,在增删改时让其返回master数据源的key,查询时slave数据源的key即可。
2. 如何判断即将执行的SQL是增,还是删,还是改,还是查?以便去修改数据源
有深入学习过Mybatis的肯定就可以想到,就是去编写一个Mybatis插件,拦截每一个数据库操作,根据条件判断哪个是增删改查。
可以看我的关于Mybatis的文章
通过上面的分析,我们总结一下我们要做的步骤
- AbstractRoutingDataSource 实现类,实现determineCurrentLookupKey方法
- 加载两个数据源(master,slave)将他们配置进AbstractRoutingDataSource的实现类
- 编写Mybatis插件去判断应该使用的数据源
上面有了步骤,我们按照步骤编写的过程中一定会发生很多问题,就像唐僧取经,去西天的路上你一定会遇到九九八十一难,但是你只要有了方向(西天),剩下的去克服了困难就一定能上西天,如果你没有方向,经历一万次劫难也到不了西天,思路永远比实现更加重要。
步骤
这里先进行一主一从架构的实现
1. AbstractRoutingDataSource 实现类,实现determineCurrentLookupKey方法
首先创建一个DynamicDataSourceHolder类去持有动态数据源的KEY
package com.csdn.shop.dao.split;
/**
* 动态数据源类持有者,线程安全
* 持有动态数据源的信息,以及修改清理数据源
*/
public class DynamicDataSourceHolder {
//线程安全
private static ThreadLocal<String> contextHolder = new ThreadLocal<String>();
public static final String DB_MASTER = "master";
public static final String DB_SLAVE = "slave";
/**
* 0
* 获取线程的dbType
*
* @return
*/
public static String getDbType() {
String db = contextHolder.get();
if (db == null)
db = DB_MASTER;
System.out.println("所使用的数据源为:" + db);
return db;
}
/**
* 设置线程的dbType
*
* @param datasource 数据源类型
*/
public static void setDbType(String datasource) {
contextHolder.set(datasource);
}