spring在管理数据源的时候是直接使用DataSourceTransactionManager,并将datasource放入进去,所以在多数据源的时候,只要在这个时间节点前,改变DataSource就行了。
spring的多数据源支持类是一个叫AbstractRoutingDataSource的抽象类
捡几个重要属性和方法说一下
targetDataSources目前数据源是一个map集合
defaultTargetDataSource默认数据源
lenientFallback当目标数据源未找到时,是否使用默认数据源,默认为true
resolvedDataSources和resolvedDefaultDataSource这两个属性是将目标数据源通过afterPropertiesSet方法进行重新赋值
主要的方式是determineTargetDataSource
这个方法是在目标查询是确定该数据源是使用哪个数据源
determineCurrentLookupKey获取目标数据源,是一个抽象方法,如果我们动态该变数据源的时候,就需要重写这个方法
所以在这种情况下,我们需要写一个动态获取数据源的类DynamicDataSource
public class DynamicDataSource extends AbstractRoutingDataSource {
@Override
protected Object determineCurrentLookupKey() {
return DbContextHolder.getDb();
}
@Override
protected DataSource determineTargetDataSource() {
DataSource dataSource = super.determineTargetDataSource();
return dataSource;
}
}
这个类继承AbstractRoutingDataSource,并重写其中的determineCurrentLookupKey方法,因为这个方法要获取数据源的名称,那么再定义个数据源获取类DbContextHolder
public class DbContextHolder {
private static final ThreadLocal<String> contextHolder = new ThreadLocal<String>();
public static void setDb(String db) {
contextHolder.set(db);
}
public static String getDb() {
return contextHolder.get();
}
public static void cleanDb() {
contextHolder.remove();
}
}
这样既可
然后在配置文件里面新增多数据源配置
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
<property name="driverClassName" value="${master.driverClassName}" />
<property name="url" value="${master.url}" />
<property name="username" value="${master.username}" />
<property name="password" value="${master.password}" />
<property name="initialSize" value="0" />
<!-- 连接池最大使用连接数量 -->
<property name="maxActive" value="40" />
<!-- 连接池最大空闲 -->
<property name="maxIdle" value="40" />
<!-- 连接池最小空闲 -->
<property name="minIdle" value="0" />
<!-- 获取连接最大等待时间 -->
<property name="maxWait" value="60000" />
</bean>
<bean id="dataSourceAssist1" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
<property name="driverClassName" value="${assist.driverClassName}" />
<property name="url" value="${assist.url}" />
<property name="username" value="${assist.username}" />
<property name="password" value="${assist.password}" />
<property name="initialSize" value="0" />
<!-- 连接池最大使用连接数量 -->
<property name="maxActive" value="40" />
<!-- 连接池最大空闲 -->
<property name="maxIdle" value="40" />
<!-- 连接池最小空闲 -->
<property name="minIdle" value="0" />
<!-- 获取连接最大等待时间 -->
<property name="maxWait" value="60000" />
</bean>
<bean id="dataSourceNew2" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
<property name="driverClassName" value="${new.driverClassName}" />
<property name="url" value="${new.url}" />
<property name="username" value="${new.username}" />
<property name="password" value="${new.password}" />
<property name="initialSize" value="0" />
<!-- 连接池最大使用连接数量 -->
<property name="maxActive" value="40" />
<!-- 连接池最大空闲 -->
<property name="maxIdle" value="40" />
<!-- 连接池最小空闲 -->
<property name="minIdle" value="0" />
<!-- 获取连接最大等待时间 -->
<property name="maxWait" value="60000" />
</bean>
多数据源配置完毕后,配置动态获取数据源的bean
<bean id="dynamicDataSource" class="com.fyz.boss.common.datasouces.DynamicDataSource">
<property name="targetDataSources">
<map key-type="java.lang.String">
<entry key="dataSource" value-ref="dataSource" />
<entry key="dataSourceAssist1" value-ref="dataSourceAssist1" />
<entry key="dataSourceNew2" value-ref="dataSourceNew2" />
</map>
</property>
<property name="defaultTargetDataSource" ref="dataSource" />
</bean>
这个时候,将SqlSessionFactoryBean和DataSourceTransactionManager的DataSource属性引用为动态数据源的bean
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dynamicDataSource" />
<property name="configLocation" value="classpath:mybatis/mybatis-config.xml" />
<property name="mapperLocations">
<list>
<value>classpath:com/fyz/boss/**/*.xml</value>
</list>
</property>
</bean>
<bean id="txManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dynamicDataSource" />
</bean>
测试环节
@Test
public void testDb() {
System.out.println("------------------");
if(memberServiceImpl == null){
System.out.println("123");
}
DbContextHolder.setDb("dataSourceNew2");
Member m = new Member();
m.setAccountName("22213");
m.setMemberName("gui");
System.out.println(DbContextHolder.getDb());
System.out.println(memberServiceImpl.add(m));
//DbContextHolder.setDb("dataSource");
}
这个时候可以动态的改变数据源了,如果在配置文件中将lenientFallback属性设置为false的话,测试的配置中如果找不到dataSourceNew2将会报错