Spring+Mybatis多資料來源配置(四)——AbstractRoutingDataSource實現資料來源動態切換
阿新 • • 發佈:2019-02-18
有時候需要在程式中動態切換資料來源,那麼這個系列的之前的博文所闡述的方法就不再使用了,總不能通過程式更改config.properties檔案的dataSource的值,然後再重啟web伺服器以便載入applicationContext.xml檔案。這裡講訴的是如何利用AbstractRoutingDataSource進行資料來源動態切換。
首先上applicationContext.xml檔案:
我們可以觀察到檔案中多了一段:<?xml version="1.0" encoding="UTF-8" ?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation=" http://www.springframework.org/schema/beans classpath:/org/springframework/beans/factory/xml/spring-beans-3.0.xsd http://www.springframework.org/schema/aop classpath:/org/springframework/aop/config/spring-aop-3.0.xsd http://www.springframework.org/schema/context classpath:/org/springframework/context/config/spring-context-3.0.xsd http://www.springframework.org/schema/tx classpath:/org/springframework/transaction/config/spring-tx-3.0.xsd"> <!-- IoC配置 --> <!-- 掃描類包,將標註Spring註解的類自動轉化Bean,同時完成Bean的注入 --> <context:component-scan base-package="com.shr.dao" /> <context:component-scan base-package="com.shr.service" /> <!-- DAO配置 --> <context:property-placeholder location="classpath:config.properties"/> <bean id="mysql" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"> <property name="driverClassName" value="${mysql_driver}"/> <property name="url" value="${mysql_url}"/> <property name="username" value="${mysql_username}"/> <property name="password" value="${mysql_password}"/> </bean> <bean id="oracle" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"> <property name="driverClassName" value="${ora_driver}"/> <property name="url" value="${ora_url}"/> <property name="username" value="${ora_username}"/> <property name="password" value="${ora_password}"/> </bean> <bean id="dataSource" class="com.shr.dao.datasource.DataSources"> <property name="targetDataSources"> <map key-type="java.lang.String"> <entry value-ref="mysql" key="MYSQL"></entry> <entry value-ref="oracle" key="ORACLE"></entry> </map> </property> <property name="defaultTargetDataSource" ref="mysql"></property> </bean> <bean id="vendorProperties" class="org.springframework.beans.factory.config.PropertiesFactoryBean"> <property name="properties"> <props> <prop key="Oracle">oracle</prop> <prop key="MySQL">mysql</prop> </props> </property> </bean> <bean id="databaseIdProvider" class="org.apache.ibatis.mapping.VendorDatabaseIdProvider"> <property name="properties" ref="vendorProperties" /> </bean> <bean name="myBatisSQLInterceptor" class="com.shr.dao.MyBatisSQLInterceptor"></bean> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="dataSource" ref="dataSource" /> <property name="typeAliasesPackage" value="com.shr.dao.pojo,com.shr.dao.model" /> <property name="databaseIdProvider" ref="databaseIdProvider" /> <property name="mapperLocations"> <list> <value>classpath:com/shr/dao/resources/mappers/*_mapper.xml</value> </list> </property> <!-- <property name="configLocation" value="/WEB-INF/mybatis-config.xml"/> --> <property name="typeHandlersPackage" value="com.shr.dao" /> <property name="plugins"> <list> <ref bean="myBatisSQLInterceptor"/> </list> </property> </bean> <!-- 配置事務管理器 --> <tx:annotation-driven/> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="${dataSource}"/> </bean> <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <property name="basePackage" value="com.shr.dao.mapper"/> <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/> <!-- <property name="markerInterface" value="com.shr.dao.mapper.ITemplateMapper"/> --> </bean> </beans>
而且sqlSessionFactory的dataSource是關聯到上面這段內容的,而不是通過${dataSource}讀取config.properties檔案的內容獲取的。<bean id="dataSource" class="com.shr.dao.datasource.DataSources"> <property name="targetDataSources"> <map key-type="java.lang.String"> <entry value-ref="mysql" key="MYSQL"></entry> <entry value-ref="oracle" key="ORACLE"></entry> </map> </property> <property name="defaultTargetDataSource" ref="mysql"></property> </bean>
這個com.shr.dao.datasource.DataSources是自定義的類,繼承自AbstractRoutingDataSource類,實現其determineCurrentLookupKey()方法。
程式碼如下:
package com.shr.dao.datasource; import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource; public class DataSources extends AbstractRoutingDataSource { @Override protected Object determineCurrentLookupKey() { return DataSourceSwitch.getDataSourceType(); } }
package com.shr.dao.datasource;
public class DataSourceSwitch
{
private static final ThreadLocal<String> contextHolder = new ThreadLocal<String>();
public static void setDataSourceType(String dataSourceType)
{
contextHolder.set(dataSourceType);
}
public static String getDataSourceType()
{
return contextHolder.get();
}
public static void clearDataSourceType()
{
contextHolder.remove();
}
}
package com.shr.dao.datasource;
public class DataSourceInstances
{
public static final String MYSQL="MYSQL";
public static final String ORACLE="ORACLE";
}
同樣,我們通過一個junit測試用例進行驗證:
package com.shr.dao.datasource;
import java.util.List;
import javax.inject.Inject;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.transaction.TransactionConfiguration;
import org.springframework.transaction.annotation.Transactional;
import com.shr.dao.datasource.DataSourceInstances;
import com.shr.dao.datasource.DataSourceSwitch;
import com.shr.dao.model.userManage.UserListInfo;
import com.shr.service.userManage.UserManageService;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("file:WebContent/WEB-INF/applicationContext.xml")
@Transactional
@TransactionConfiguration(transactionManager="transactionManager",defaultRollback=false)
public class DynamicDataSourceTest
{
@Inject
private UserManageService userManageService;
@Test
public void test()
{
DataSourceSwitch.setDataSourceType(DataSourceInstances.MYSQL);
List<UserListInfo> list = userManageService.getUserListInfo();
for(UserListInfo user : list)
{
System.out.println(user.getUser_name());
}
}
}
通過改變DataSourceSwitch.setDataSourceType(DataSourceInstances.ORACLE);可以轉換不同的資料來源.