Spring 配置多個(gè)數(shù)據(jù)源,并實(shí)現(xiàn)動(dòng)態(tài)切換

1.配置兩個(gè)不同的數(shù)據(jù)源,如下(由于項(xiàng)目使用的是druid數(shù)據(jù)庫(kù)連接,配置可以會(huì)復(fù)雜點(diǎn)比較):

<!-- 數(shù)據(jù)源配置1 -->

? ? <bean id="testDataSource1" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">

? ? ? <property name="driverClassName" value="${db.driver}" />

? ? ? ? <property name="url" value="${unity.db.jdbc.url}" />

? ? ? <property name="username" value="${db.login.name}"></property>

? ? ? <property name="password" value="${db.login.password}" />

? ? ? <property name="filters"? value="${db.filters}"></property>

? ? ? <property name="maxActive" value="${db.pool.maxActive}"></property>

? ? ? <property name="initialSize" value="${db.pool.initialSize}"></property>

? ? ? <property name="minIdle" value="${db.pool.minIdle}"></property>

? ? ? <property name="maxWait" value="${db.maxWait}"></property>? ?

? ? ? <property name="timeBetweenEvictionRunsMillis" value="${db.timeBetweenEvictionRunsMillis}"></property>

? ? ? <property name="minEvictableIdleTimeMillis" value="${db.minEvictableIdleTimeMillis}"></property>

? ? ? <property name="validationQuery" value="${db.validationQuery}"></property>

? ? ? <property name="testWhileIdle" value="${db.testWhileIdle}"></property>

? ? ? <property name="testOnBorrow" value="${db.testOnBorrow}"></property>

? ? ? <property name="testOnReturn" value="${db.testOnReturn}"></property>

? ? ? <property name="poolPreparedStatements" value="${db.poolPreparedStatements}"></property>

? ? ? <property name="maxOpenPreparedStatements" value="${db.maxOpenPreparedStatements}"></property>

? ? ? <!-- 監(jiān)控?cái)?shù)據(jù)庫(kù) -->

? ? ? ? <property name="proxyFilters">

? ? ? ? ? ? <list>

? ? ? ? ? ? ? ? <ref bean="log-filter" />

? ? ? ? ? ? </list>

? ? ? ? </property>


? </bean>


<!-- 數(shù)據(jù)源配置2 -->

? ? <bean id="testDataSource2" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">

? ? ? <property name="driverClassName" value="${db.driver}" />

? ? ? ? <property name="url" value="${pub.db.jdbc.url}" />

? ? ? <property name="username" value="${db.login.name}"></property>

? ? ? <property name="password" value="${db.login.password}" />

? ? ? <property name="filters"? value="${db.filters}"></property>

? ? ? <property name="maxActive" value="${db.pool.maxActive}"></property>

? ? ? <property name="initialSize" value="${db.pool.initialSize}"></property>

? ? ? <property name="minIdle" value="${db.pool.minIdle}"></property>

? ? ? <property name="maxWait" value="${db.maxWait}"></property>? ?

? ? ? <property name="timeBetweenEvictionRunsMillis" value="${db.timeBetweenEvictionRunsMillis}"></property>

? ? ? <property name="minEvictableIdleTimeMillis" value="${db.minEvictableIdleTimeMillis}"></property>

? ? ? <property name="validationQuery" value="${db.validationQuery}"></property>

? ? ? <property name="testWhileIdle" value="${db.testWhileIdle}"></property>

? ? ? <property name="testOnBorrow" value="${db.testOnBorrow}"></property>

? ? ? <property name="testOnReturn" value="${db.testOnReturn}"></property>

? ? ? <property name="poolPreparedStatements" value="${db.poolPreparedStatements}"></property>

? ? ? <property name="maxOpenPreparedStatements" value="${db.maxOpenPreparedStatements}"></property>

? ? ? <!-- 監(jiān)控?cái)?shù)據(jù)庫(kù) -->

? ? ? ? <property name="proxyFilters">

? ? ? ? ? ? <list>

? ? ? ? ? ? ? ? <ref bean="log-filter" />

? ? ? ? ? ? </list>

? ? ? ? </property>


? </bean>

2.定義一個(gè)類繼承AbstractRoutingDataSource實(shí)現(xiàn)determineCurrentLookupKey方法,該方法可以實(shí)現(xiàn)數(shù)據(jù)庫(kù)的動(dòng)態(tài)切換,如下:

public class DynamicDataSource extends AbstractRoutingDataSource {

@Override

protected Object determineCurrentLookupKey() {

return DataSourceContextHolder.getDataSourceType();

}

}

3.定義一個(gè)可以設(shè)置當(dāng)前線程的變量的工具類,用于設(shè)置對(duì)應(yīng)的數(shù)據(jù)源名稱:

public class DataSourceContextHolder {

private static final ThreadLocal<String> contextHolder = new ThreadLocal<String>();

/**

* @Description: 設(shè)置數(shù)據(jù)源類型

* @param dataSourceType? 數(shù)據(jù)庫(kù)類型

* @return void

* @throws

*/

public static void setDataSourceType(String dataSourceType) {

contextHolder.set(dataSourceType);

}

/**

* @Description: 獲取數(shù)據(jù)源類型

* @param

* @return String

* @throws

*/

public static String getDataSourceType() {

return contextHolder.get();

}

/**

* @Description: 清除數(shù)據(jù)源類型

* @param

* @return void

* @throws

*/

public static void clearDataSourceType() {

contextHolder.remove();

}

}

然后在spring中配置,如下:

<!-- 編寫spring 配置文件的配置多數(shù)源映射關(guān)系 -->

<bean class="com.sino.access.database.DynamicDataSource" id="dataSource">

<property name="targetDataSources">

<map key-type="java.lang.String">

<entry value-ref="testDataSource1" key="<span style="font-family: Arial, Helvetica, sans-serif;">testDataSource1</span><span style="font-family: Arial, Helvetica, sans-serif;">"></entry></span>

<entry value-ref="testDataSource2" key="testDataSource2"></entry>

</map>

</property>

<property name="defaultTargetDataSource" ref="testDataSource1">

</property>

</bean>

這樣配置兩個(gè)數(shù)據(jù)源對(duì)應(yīng)的key分別為testDataSource1和testDataSource2,默認(rèn)數(shù)據(jù)庫(kù)是testDataSource。

4.完成以上步驟后,如果沒(méi)有數(shù)據(jù)庫(kù)的事務(wù)管理,已經(jīng)可以實(shí)現(xiàn)數(shù)據(jù)庫(kù)的動(dòng)態(tài)切換了。但是如果涉及到數(shù)據(jù)庫(kù)的事務(wù)管理,需要在數(shù)據(jù)庫(kù)事務(wù)開啟切換數(shù)據(jù)庫(kù),

否則數(shù)據(jù)庫(kù)的切換只能在下次數(shù)據(jù)庫(kù)操作時(shí)才生效。可以定義一個(gè)aop處理類在數(shù)據(jù)庫(kù)事務(wù)開啟之前切換數(shù)據(jù)庫(kù),如下:

public class DataSourceAspect implements MethodBeforeAdvice,AfterReturningAdvice

{

@Override

public void afterReturning(Object returnValue, Method method,

Object[] args, Object target) throws Throwable {

// TODO Auto-generated method stub

DataSourceContextHolder.clearDataSourceType();

}

@Override

public void before(Method method, Object[] args, Object target)

throws Throwable {

if (method.isAnnotationPresent(DataSource.class))

{

DataSource datasource = method.getAnnotation(DataSource.class);

DataSourceContextHolder.setDataSourceType(datasource.name());

}

else

{

DataSourceContextHolder.setDataSourceType(SinoConstant.DataSourceType.unityDataSource.toString());

}

}

}

5.設(shè)置數(shù)據(jù)庫(kù)事務(wù)切面和切換數(shù)據(jù)庫(kù)切面執(zhí)行的順序,如下:

<aop:config>

<aop:pointcut id="transactionPointCut" expression="execution(* com.test.service.*.*(..))" />

<aop:advisor pointcut-ref="transactionPointCut"

advice-ref="txAdvice" order="2" />

<aop:advisor advice-ref="dataSourceExchange" pointcut-ref="transactionPointCut" order="1"/>

</aop:config>

利用aop的order屬性設(shè)置執(zhí)行的順序,這樣實(shí)現(xiàn)了帶事務(wù)管理的spring數(shù)據(jù)庫(kù)動(dòng)態(tài)切換。

歡迎工作一到五年的Java工程師朋友們加入Java架構(gòu)開發(fā):855801563 獲取更多免費(fèi)視頻教程。

合理利用自己每一分每一秒的時(shí)間來(lái)學(xué)習(xí)提升自己,不要再用"沒(méi)有時(shí)間“來(lái)掩飾自己思想上的懶惰!趁年輕,使勁拼,給未來(lái)的自己一個(gè)交代

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見(jiàn)模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 134,837評(píng)論 18 139
  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語(yǔ)法,類相關(guān)的語(yǔ)法,內(nèi)部類的語(yǔ)法,繼承相關(guān)的語(yǔ)法,異常的語(yǔ)法,線程的語(yǔ)...
    子非魚_t_閱讀 31,739評(píng)論 18 399
  • 近日,迷上寫作,好像一個(gè)酒鬼迷上了酒。也上了一個(gè)輔導(dǎo)班,學(xué)習(xí)如何寫爆款文字,如何成為標(biāo)題黨,如何吸引人的眼球…… ...
    紅色的魚兒閱讀 422評(píng)論 5 8
  • 致陶行知 幾載飄零苦修學(xué), 一朝功成誓歸國(guó)。 目華夏之瘡痍, 欲救生民與水火。 不慕俗世之功名, 不羨鴻儒之談笑。...
    我知桑榆非晚閱讀 413評(píng)論 0 0
  • 有點(diǎn)累了
    菇?jīng)鲩L(zhǎng)蘑菇閱讀 138評(píng)論 0 0