用DynamicDataSource類輔助切換多數據源
實現AbstractRoutingDataSource接口,在類中定義
public static final String plateBaseDataSource= "plateBaseDataSource";
public static final String lgCommonDataSource= "lgCommonDataSource";
public static final String subApplicationDataSource= "subApplicationDataSource";
public static final ThreadLocal<String> contextHolder = new ThreadLocal<String>(){};
切換與清空數據緣方法為
public static void clearCustomerDataSource(){ contextHolder.remove(); } public static void setCustomerDataSource(String customerType){ contextHolder.set(customerType); }
對應配置文件中,數據源定義為
<bean id="plateBaseDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"> <property name="driverClassName" value="${plateBase.driverClassName}" /> <property name="url" value="${plateBase.url}" /> <property name="username" value="${plateBase.uname}" /> <property name="password" value="${plateBase.password}" /> <!-- 連接池啟動時的初始值 --> <property name="initialSize" value="${plateBase.initialSize}" /> <!-- 連接池的最大值 --> <property name="maxActive" value="${plateBase.maxActive}" /> <!-- 最大空閑值.當經過一個高峰時間后,連接池可以慢慢將已經用不到的連接慢慢釋放一部分,一直減少到maxIdle為止 --> <property name="maxIdle" value="${plateBase.maxIdle}" /> <!-- 最小空閑值.當空閑的連接數少於閥值時,連接池就會預申請去一些連接,以免洪峰來時來不及申請 --> <property name="minIdle" value="${plateBase.minIdle}" /> <property name="validationQuery" value="select 1 from dual"></property> </bean> <bean id="lgCommonDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"> <property name="driverClassName" value="${lgCommon.driverClassName}" /> <property name="url" value="${lgCommon.url}" /> <property name="username" value="${lgCommon.uname}" /> <property name="password" value="${lgCommon.password}" /> <!-- 連接池啟動時的初始值 --> <property name="initialSize" value="${lgCommon.initialSize}" /> <!-- 連接池的最大值 --> <property name="maxActive" value="${lgCommon.maxActive}" /> <!-- 最大空閑值.當經過一個高峰時間后,連接池可以慢慢將已經用不到的連接慢慢釋放一部分,一直減少到maxIdle為止 --> <property name="maxIdle" value="${lgCommon.maxIdle}" /> <!-- 最小空閑值.當空閑的連接數少於閥值時,連接池就會預申請去一些連接,以免洪峰來時來不及申請 --> <property name="minIdle" value="${lgCommon.minIdle}" /> <property name="validationQuery" value="select 1 from dual"></property> </bean>
定義DataSource為
<bean id="dataSource" class="heb.ysbs.utils.lgcommon.DynamicDataSource">
<property name="defaultTargetDataSource" ref="${defaultTargetDataSource}"/>
<property name="customDefaultDataSource" value="${defaultTargetDataSource}"/>
<property name="customLgBaseLogTableName" value="${customLgBaseLogTableName}"/>
<property name="targetDataSources" >
<map>
<entry key="plateBaseDataSource" value-ref="plateBaseDataSource"/>
<entry key="lgCommonDataSource" value-ref="lgCommonDataSource"/>
</map>
</property>
</bean>
jdbctemplate常規定義,沒什么好講
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource" />
</bean>
以上為數據源切換部分 ,這時切換數據源可直接調用DynamicDataSource.clearCustomerDataSource,在配置事務后,進入事務線程后jdbc得到默認DataSource,DynamicDataSource方法設置數據源在事務中執行的jdbc中不體現(線程問題,一知半解)
解決方法是在事務開啟前切換數據源,用aop增強
定義工具類
<bean id="dataSourceExchange" class="fasp.utils.lgcommon.DataSourceExchange"></bean>
定義切片,排序在事務之前 :事務切點order=2,
<aop:config proxy-target-class="true">
<aop:pointcut id="dataSourcetransactionPointcut" expression="(execution(* fasp.service.lgcommon..*.*(..))) )" />
<aop:aspect id="aspect" ref="dataSourceExchange" order="1" >
<aop:before method="before" pointcut-ref="dataSourcetransactionPointcut" />
<aop:after method="after" pointcut-ref="dataSourcetransactionPointcut" />
</aop:aspect>
</aop:config>
個人習慣,感覺定義兩個切點靈活,這里沒有必要每個方法都進行數據切換如果也用 在一個aop:pointcut 定義兩個aop:advisor就還要在攔截器中判斷調用方法,其他資料中看到的
invoke方法
package com.lei.demo.aop.schema; import java.lang.reflect.Method; import org.aopalliance.intercept.MethodInterceptor; import org.aopalliance.intercept.MethodInvocation; public class HelloAroundAdvice implements MethodInterceptor { public Object invoke(MethodInvocation arg0) throws Throwable { System.out.println("++++++before advice"); arg0.proceed(); System.out.println("++++++after advice"); return null; } }
工具類DataSourceExchange中方法
1 /** 2 * 事務加載前執行 3 * 切換數據源 4 * @param call 5 */ 6 public void before(JoinPoint call){ 7 8 Object[] obj=call.getArgs();//參數集合 9 String dataSourceName=(String)(obj[0]);//規則:默認第一個參數為datasourcename 10 //Signature signature=call.getSignature(); //參數類型集合 11 // String [] argNames= ( (MethodSignature) signature ).getParameterNames();//參數名 12 DynamicDataSource.setCustomerDataSource( dataSourceName); 13 14 } 15 /** 16 * 事務加載前執行 17 * 清空數據源 18 * @param call 19 */ 20 public void after(JoinPoint call){ 21 DynamicDataSource.clearCustomerDataSource(); 22 //String parameter= DynamicDataSource.getCustomDefaultDataSource(); 23 //DynamicDataSource.setCustomerDataSource(parameter); 24 } 25 }
