Spring配置多個(gè)數(shù)據(jù)源并實(shí)現(xiàn)動(dòng)態(tài)切換示例
1.配置兩個(gè)不同的數(shù)據(jù)源,如下(由于項(xiàng)目使用的是druid數(shù)據(jù)庫連接,配置可以會(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ù)庫 --> <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ù)庫 --> <property name="proxyFilters"> <list> <ref bean="log-filter" /> </list> </property> </bean>
2.定義一個(gè)類繼承AbstractRoutingDataSource實(shí)現(xiàn)determineCurrentLookupKey方法,該方法可以實(shí)現(xiàn)數(shù)據(jù)庫的動(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ù)庫類型 * @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> </bean>
這樣配置兩個(gè)數(shù)據(jù)源對(duì)應(yīng)的key分別為testDataSource1和testDataSource2,默認(rèn)數(shù)據(jù)庫是testDataSource。
4.完成以上步驟后,如果沒有數(shù)據(jù)庫的事務(wù)管理,已經(jīng)可以實(shí)現(xiàn)數(shù)據(jù)庫的動(dòng)態(tài)切換了。但是如果涉及到數(shù)據(jù)庫的事務(wù)管理,需要在數(shù)據(jù)庫事務(wù)開啟切換數(shù)據(jù)庫,
否則數(shù)據(jù)庫的切換只能在下次數(shù)據(jù)庫操作時(shí)才生效??梢远x一個(gè)aop處理類在數(shù)據(jù)庫事務(wù)開啟之前切換數(shù)據(jù)庫,如下:
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ù)庫事務(wù)切面和切換數(shù)據(jù)庫切面執(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ù)庫動(dòng)態(tài)切換。
以上就是本文的全部內(nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
EasyExcel實(shí)現(xiàn)讀寫Excel文件的示例代碼
EasyExcel是阿里巴巴開源的一個(gè)excel處理框架,以使用簡單、節(jié)省內(nèi)存著稱。它可以在盡可能節(jié)約內(nèi)存的情況下支持讀寫百M(fèi)的Excel,所以本文就將利用它實(shí)現(xiàn)讀寫Excel文件,感興趣的可以了解一下2022-08-08springBoot server.port=-1的含義說明
這篇文章主要介紹了springBoot server.port=-1的含義說明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-08-08Java實(shí)現(xiàn)各種文件類型轉(zhuǎn)換方式(收藏)
這篇文章主要介紹了Java?各種文件類型轉(zhuǎn)換的方法,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-03-03nodejs連接dubbo服務(wù)的java工程實(shí)現(xiàn)示例
這篇文章主要介紹了在項(xiàng)目遷移中,nodejs連接dubbo服務(wù)的java工程實(shí)現(xiàn)示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步2022-03-03java二進(jìn)制運(yùn)算基礎(chǔ)知識(shí)點(diǎn)詳解
在本文里小編給大家分享了關(guān)于java二進(jìn)制運(yùn)算基礎(chǔ)知識(shí)點(diǎn)以及實(shí)例代碼內(nèi)容,需要的朋友們參考學(xué)習(xí)下。2019-08-08