引语

有时候我们需要切换多个数据源,来使用不同的数据,这时候我们可以使用mybatis的DataSourceTransactionManager来实现数据源的切换.
下面我们一起来看下来一个简单的实现方式.

步骤:

1.首先我们jdbc.properties(名字不一定是这个,代指保存数据库连接信息的配置文件)里面有多个数据源,一个老的一个新的

1
2
3
4
5
6
7
8
9
jdbc.driver:com.mysql.Driver
jdbc.url:xxx
jdbc.username:xxx
jdbc.password:xxx

old.jdbc.driver:com.mysql.Driver
old.jdbc.url:xxx
old.jdbc.username:xxx
old.jdbc.password:xxx

2.写一个CustomerContextHolder,里面的属性ThreadLocal保存的就是当前数据源的key,每一个数据源对应一个key,这里默认是新数据库-new,另一个是老数据库-old

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class CustomerContextHolder {
public static final String DATA_SOURCE_DEFAULT = "new";
public static final String DATA_SOURCE_OLD = "old";
private static final ThreadLocal<String> contextHolder = new ThreadLocal<>();

public static void setCustomerType(String customerType) {
contextHolder.set(customerType);
}

public static String getCustomerType() {
return contextHolder.get();
}

public static void clearCustomerType() {
contextHolder.remove();
}
}

3.写一个叫DynamicDataSource的类,继承AbstractRoutingDataSource,AbstractRoutingDataSource里面有一个determineCurrentLookupKey方法,是决定
使用哪个数据源key.(相当于说每个数据源有一个key的标识,返回不同的key就是选择了不同的数据源).

1
2
3
4
5
6
7
8
public class DynamicDataSource extends AbstractRoutingDataSource {

@Override
protected Object determineCurrentLookupKey() {
return CustomerContextHolder.getCustomerType();
}

}

4.然后将spring-datasource.xml的配置配好

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.springframework.org/schema/beans"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"
default-lazy-init="true">

<!-- DataSource数据 -->
<bean id="newDataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
<property name="name" value="wxwwt"/>
<property name="driverClassName" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
<property name="maxActive" value="20"/>
<property name="minIdle" value="2"/>
<property name="initialSize" value="2"/>
<property name="validationQuery" value="SELECT 1"/>
<property name="testOnBorrow" value="false"/>
<property name="testOnReturn" value="false"/>
<property name="testWhileIdle" value="true"/>
<property name="timeBetweenEvictionRunsMillis" value="60000"/>
<property name="minEvictableIdleTimeMillis" value="300000"/>
<property name="defaultAutoCommit" value="true"/>
<property name="removeAbandoned" value="true"/>
<property name="removeAbandonedTimeout" value="60"/>
<property name="logAbandoned" value="true"/>
<property name="filters" value="stat"/>
</bean>

<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.wxwwt.web.db.mapper"/>
</bean>

<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="mapperLocations">
<list>
<value>classpath*:sqlmap/**/*.xml</value>
</list>
</property>
<property name="dataSource" ref="dynamicDataSource"/>

</bean>

<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
<constructor-arg index="0" ref="sqlSessionFactory"/>
</bean>

<bean id="oldDataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
<property name="name" value="wxwwt"/>
<property name="driverClassName" value="${old.jdbc.driver}"/>
<property name="url" value="${old.jdbc.url}"/>
<property name="username" value="${old.jdbc.username}"/>
<property name="password" value="${old.jdbc.password}"/>
<property name="maxActive" value="20"/>
<property name="minIdle" value="2"/>
<property name="initialSize" value="2"/>
<property name="validationQuery" value="SELECT 1"/>
<property name="testOnBorrow" value="false"/>
<property name="testOnReturn" value="false"/>
<property name="testWhileIdle" value="true"/>
<property name="timeBetweenEvictionRunsMillis" value="60000"/>
<property name="minEvictableIdleTimeMillis" value="300000"/>
<property name="defaultAutoCommit" value="true"/>
<property name="removeAbandoned" value="true"/>
<property name="removeAbandonedTimeout" value="60"/>
<property name="logAbandoned" value="true"/>
<property name="filters" value="stat"/>
</bean>

<!-- 动态数据源 -->
<bean id="dynamicDataSource" class="com.wxwwt.web.config.DynamicDataSource">
<property name="targetDataSources">
<map key-type="java.lang.String">
<entry value-ref="newDataSource" key="new"/>
<entry value-ref="oldDataSource" key="old"/>
</map>
</property>
<property name="defaultTargetDataSource" ref="newDataSource">
</property>
</bean>


<bean id="txManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dynamicDataSource"/>
</bean>
</beans>

里面配置好数据源newDataSource,oldDataSource.重点是dynamicDataSource里面配置好拥有的数据源,
然后将dynamicDataSource配置到DataSourceTransactionManager里面就大功告成了.

5.使用的使用只需要CustomerContextHolder.setCustomerType(CustomerContextHolder.DATA_SOURCE_OLD);切换到老数据源,因为默认是新数据源.
如果要切换回来就CustomerContextHolder.clearCustomerType().清除掉ThreadLocal中保存的信息.又因为切换数据源的key是在ThreadLocal中的所以是只和线程有关,
一个线程选择老数据源,并不会影响到其他的线程.