正確可行的解決方法:使用Spring提供的AbstractRoutingDataSource類來根據請求路由到不一樣的數據源。具體作法是
先設置兩個不一樣的dataSource表明不一樣的數據源,再建一個總的dynamicDataSource,根據不一樣的請求去設置dynamicDataSource。代碼以下:html
配置文件spring-mybatis.xmljava
<!--統一的dataSource--> <bean id="dynamicDataSource" class="path.to.DynamicDataSource" > <property name="targetDataSources"> <map key-type="java.lang.String"> <!--經過不一樣的key決定用哪一個dataSource--> <entry value-ref="dataSource" key="dataSource"></entry> <entry value-ref="mssqlDataSource" key="mssqlDataSource"></entry> </map> </property> <!--設置默認的dataSource--> <property name="defaultTargetDataSource" ref="dataSource"> </property> </bean> <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"> <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="initialSize" value="${jdbc.initialSize}"></property> <!-- 鏈接池最大數量 --> <property name="maxActive" value="${jdbc.maxActive}"></property> <!-- 鏈接池最大空閒 --> <property name="maxIdle" value="${jdbc.maxIdle}"></property> <!-- 鏈接池最小空閒 --> <property name="minIdle" value="${jdbc.minIdle}"></property> <!-- 獲取鏈接最大等待時間 --> <property name="maxWait" value="${jdbc.maxWait}"></property> </bean> <!--電影票數據庫是mssql2008,單獨的數據庫,配置以下--> <bean id="mssqlDataSource" class="org.apache.commons.dbcp.BasicDataSource"> <property name="driverClassName" value="${jdbc-mssql.driver}" /> <property name="url" value="${jdbc-mssql.url}" /> <property name="username" value="${jdbc-mssql.username}" /> <property name="password" value="${jdbc-mssql.password}" /> <!-- 初始化鏈接大小 --> <property name="initialSize" value="${jdbc.initialSize}"></property> <!-- 鏈接池最大數量 --> <property name="maxActive" value="${jdbc.maxActive}"></property> <!-- 鏈接池最大空閒 --> <property name="maxIdle" value="${jdbc.maxIdle}"></property> <!-- 鏈接池最小空閒 --> <property name="minIdle" value="${jdbc.minIdle}"></property> <!-- 獲取鏈接最大等待時間 --> <property name="maxWait" value="${jdbc.maxWait}"></property> </bean> <!-- spring和MyBatis完美整合,不須要mybatis的配置映射文件 --> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="dataSource" ref="dynamicDataSource" /> <!-- 自動掃描mapping.xml文件 --> <property name="mapperLocations" value="classpath:path/to/mapping/*.xml"></property> </bean> <!-- DAO接口所在包名,Spring會自動查找其下的類 --> <bean id="mapperScannerConfigurer" class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <property name="basePackage" value="path.to.dao" /> <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"></property> </bean> <!-- (事務管理)transaction manager, use JtaTransactionManager for global tx --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dynamicDataSource" /> </bean>
DynamicDataSource.javaspring
public class DynamicDataSource extends AbstractRoutingDataSource { @Override protected Object determineCurrentLookupKey() { return CustomerContextHolder.getCustomerType(); } }
CustomerContextHolder.javasql
public class CustomerContextHolder { public static final String DATA_SOURCE_MYSQL = "dataSource"; public static final String DATA_SOURCE_MSSQL = "mssqlDataSource"; //用ThreadLocal來設置當前線程使用哪一個dataSource private static final ThreadLocal<String> contextHolder = new ThreadLocal<String>(); public static void setCustomerType(String customerType) { contextHolder.set(customerType); } public static String getCustomerType() { String dataSource = contextHolder.get(); if (StringUtils.isEmpty(dataSource)) { return DATA_SOURCE_MYSQL; }else { return dataSource; } } public static void clearCustomerType() { contextHolder.remove(); } }
ServiceImpl.java數據庫
CustomerContextHolder.setCustomerType(CustomerContextHolder.DATA_SOURCE_MSSQL);
值得注意的是在CustomerContextHolder.java中使用了ThreadLocal類的set方法來設置當前線程要選擇的dataSource,看一下set方法的源碼:apache
ThreadLocal.set()tomcat
public void set(T value) { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) map.set(this, value); else createMap(t, value); }
顯而易見,獲取當前線程,而且使用一個hashmap把須要存儲的值設置進去。由於tomcat是用的線程池來處理每一個請求,因此用ThreadLocal能夠保證線程安全問題。同時這個AbstractRoutingDataSource類也值得好好研究一下。安全
其實這個方案不單單能夠用來處理不一樣數據源的問題,同時業務量上來以後須要把數據庫進行主從分離或是把一個庫分爲多個庫,都須要用到這樣的作法。此次暴露的問題確實也瞭解了很多,繼續學習吧!mybatis
原地址:http://www.cnblogs.com/puyangsky/p/6133553.htmlapp
親測可用!