读写分离是为了减少数据库的负荷,当用户高并发访问时,绝大部分都是用户查询,少部分用户是写入到数据库的。这些我们把数据库拆分成主从两个数据库,主数据库用高性能
服务器承载高并发的用户访问并加redis缓存。在这里我不讲mysql的主从同步配置,大家可以去查下资料,我接下来重点讲怎么动态的给每个sql注入数据源。
首先大家需要先了解AbstractRoutingDataSource这个抽象类,这是spring-jdbc下的一个底层类,当sqlsession去获得一个数据库连接时会调用这个类的determineTargetDataSource()方法获得数据源。
我们先从配置文件开始说起,这是楼主实验时自己写的spring配置文件
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">
jdbc.properties文件
jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.writeUrl=jdbc:mysql://***********:3306/数据库名
jdbc.readUrl=jdbc:mysql://**********:3306/数据库名l
jdbc.username=root
jdbc.password=123456
jdbc.initialSize=30
jdbc.maxActive=100
jdbc.maxIdle=100
jdbc.minIdle=5
jdbc.maxWait=1000
首先定义一个枚举类
package com.hbut.inspiration.system;
//用户定义读写两个数据源的key值
public enum DynamicDataSourceGlobal {
READ,WRITE;
}
定义一个设置数据源的key的类,因为servlet是单例多线程的,所有定义变量的时候需考率多线程安全问题,这里楼主用到了threadlocal,用于把当前线程的用到的数据源的key存储在threadlocal里,大家想要了解threadlocal可以看楼主的 另一条博客http://blog.csdn.net/csdnzhangtao5/article/details/52932275
package com.hbut.inspiration.system;
public class DynamicDataSourceHolder { //dynamicDataSourceGlobal必须是静态的,禁止实例化多个,只能单例或者直接使用静态方法。大家可以加个恶汉单例模式
static ThreadLocal
static public DynamicDataSourceGlobal getDataSource(){
return dynamicDataSourceGlobal.get();
}
static public void putDataSource(DynamicDataSourceGlobal t){
dynamicDataSourceGlobal.set(t);
}
static public void clearDataSource(){
dynamicDataSourceGlobal.remove();
}
}
核心类,上面在spring的配置文件里已经配过
public class DynamicDataSource extends AbstractRoutingDataSource{
public Object writeDataSource;
public Object readDataSource;
public Object defaultTargetDataSource;
@Override
protected Object determineCurrentLookupKey() { //必须实现的类,用于给determineTargetDataSource()提供key值
DynamicDataSourceGlobal targetDataSource=DynamicDataSourceHolder.getDataSource(); //从DynamicDataSourceGlobal得到数据源的key值
if(targetDataSource==null || targetDataSource == DynamicDataSourceGlobal.WRITE){ //默认key值为write
return DynamicDataSourceGlobal.WRITE.name();
}else{
return DynamicDataSourceGlobal.READ.name();
}
}
public void afterPropertiesSet(){ //用于在该类所有属性都初始化完成后执行,把我们在spring定义的readdatasource,writedatasource装配到targetDataSources中
因为determineTargetDataSource()是根据determineCurrentLookupKey()它返回的key值在targetDataSources这个map中去取
对应的数据源
setDefaultTargetDataSource(writeDataSource);
Map
这样一个基本的动态获取数据源的功能就好了
要用的时候只需在每个controller调service的方法前设置就好了,例如
DynamicDataSourceHolder.putDataSource(DynamicDataSourceGlobal.WRITE); //设置数据源为写数据源
mainService.getUserInfo();
或者
DynamicDataSourceHolder.putDataSource(DynamicDataSourceGlobal.READ); //设置数据源为读数据源
mainService.getUserInfo();