1。建立DynamicDataSource類,繼承AbstractRoutingDataSource
package com.rps.dataSource; import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource; public class DynamicDataSource extends AbstractRoutingDataSource { @Override protected Object determineCurrentLookupKey() { return DynamicDataSourceHolder.getDataSource(); } }
建立DynamicDataSourceHolder類
package com.rps.dataSource; public class DynamicDataSourceHolder { /** * 注意:資料來源標識儲存線上程變數中,避免多執行緒運算元據源時互相干擾 */ private static final ThreadLocal<String> THREAD_DATA_SOURCE = new ThreadLocal<String>(); public static String getDataSource() { return THREAD_DATA_SOURCE.get(); } public static void setDataSource(String dataSource) { THREAD_DATA_SOURCE.set(dataSource); } public static void clearDataSource() { THREAD_DATA_SOURCE.remove(); } }
2.配置多資料來源
<util:properties id="jdbc" location="classpath:etc/mybatis/db.properties" /> <!-- 連線池配置開始 --> <!-- Druid連線池 --> <bean id="druidDataSourceAccount" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close" lazy-init="true"> <property name="driverClassName" value="#{jdbc.driverClassName}" /> <property name="url" value="#{jdbc.account_url}" /> <property name="username" value="#{jdbc.username}" /> <property name="password" value="#{jdbc.password}" /> </bean> <bean id="druidDataSourceCommon" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close" lazy-init="true"> <property name="driverClassName" value="#{jdbc.driverClassName}" /> <property name="url" value="#{jdbc.common_url}" /> <property name="username" value="#{jdbc.username}" /> <property name="password" value="#{jdbc.password}" /> </bean> <bean id="druidDataSourceData" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close" lazy-init="true"> <property name="driverClassName" value="#{jdbc.driverClassName}" /> <property name="url" value="#{jdbc.data_url}" /> <property name="username" value="#{jdbc.username}" /> <property name="password" value="#{jdbc.password}" /> </bean> <!-- 連線池配置結束 --> <!-- MyBatis整合開始 --> <bean id="dynamicDataSource" class="com.rps.dataSource.DynamicDataSource"> <property name="targetDataSources"> <map key-type="java.lang.String"> <entry key="account" value-ref="druidDataSourceAccount"></entry> <entry key="common" value-ref="druidDataSourceCommon"></entry> <entry key="data" value-ref="druidDataSourceData"></entry> </map> </property> </bean> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="dataSource" ref="dynamicDataSource"/> <property name="mapperLocations" value="classpath:com/rps/**/*.xml"/> <property name="configLocation" value="classpath:etc/mybatis/mybatis-config.xml"/> </bean> <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <property name="basePackage" value="com.rps" /> <property name="annotationClass" value="com.rps.annotations.MyBatisRepository" /> </bean> <!-- MyBatis整合結束 --> <!-- 配置資料庫事務開始 --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dynamicDataSource"/> </bean> <tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true" /> <!-- 配置資料庫事務結束 -->
3.在使用資料來源前,選擇資料來源:
DynamicDataSourceHolder.setDataSource("account");
或:使用spring aop 動態切換:
package com.rps.aspect; import java.lang.annotation.Annotation; import java.lang.reflect.Method; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.reflect.MethodSignature; import org.springframework.stereotype.Component; import com.rps.annotations.DataSource; import com.rps.dataSource.DynamicDataSourceHolder; @Component @Aspect public class DataSourceAspect { /** * 攔截目標方法,獲取由@DataSource指定的資料來源標識,設定到執行緒儲存中以便切換資料來源 * * @param point * @throws Exception */ @Before("execution(* com.rps.*.model.dao.*.*(..))") public void intercept(JoinPoint point) throws Exception { System.out.println("*****************************"); Class<?> target = point.getTarget().getClass(); MethodSignature signature = (MethodSignature) point.getSignature(); // 預設使用目標型別的註解,如果沒有則使用其實現介面的註解 for (Class<?> clazz : target.getInterfaces()) { resolveDataSource(clazz, signature.getMethod()); } resolveDataSource(target, signature.getMethod()); } /** * 提取目標物件方法註解和型別註解中的資料來源標識 * * @param clazz * @param method */ private void resolveDataSource(Class<?> clazz, Method method) { try { Class<?>[] types = method.getParameterTypes(); // 預設使用型別註解 if (clazz.isAnnotationPresent((Class<? extends Annotation>) DataSource.class)) { DataSource source = clazz.getAnnotation(DataSource.class); DynamicDataSourceHolder.setDataSource(source.value()); } // 方法註解可以覆蓋型別註解 Method m = clazz.getMethod(method.getName(), types); if (m != null && m.isAnnotationPresent(DataSource.class)) { DataSource source = m.getAnnotation(DataSource.class); DynamicDataSourceHolder.setDataSource(source.value()); } } catch (Exception e) { System.out.println(clazz + ":" + e.getMessage()); } } }
注:事務管理配置一定要配置在往DynamicDataSourceHolder 中注入資料來源key之前 ,否則會報 Could not open JDBC Connection for transaction; nested exception is java.lang.IllegalStateException: Cannot determine target DataSource for lookup key [null] 找不到資料來源錯誤