1.配置兩個不同的數據源,如下(由于項目使用的是druid數據庫連接,配置可以會復雜點比較):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
<!-- 數據源配置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 > <!-- 監控數據庫 --> < property name = "proxyFilters" > < list > < ref bean = "log-filter" /> </ list > </ property > </ bean > |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
<!-- 數據源配置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 > <!-- 監控數據庫 --> < property name = "proxyFilters" > < list > < ref bean = "log-filter" /> </ list > </ property > </ bean > |
2.定義一個類繼承AbstractRoutingDataSource實現determineCurrentLookupKey方法,該方法可以實現數據庫的動態切換,如下:
1
2
3
4
5
6
|
public class DynamicDataSource extends AbstractRoutingDataSource { @Override protected Object determineCurrentLookupKey() { return DataSourceContextHolder.getDataSourceType(); } } |
3.定義一個可以設置當前線程的變量的工具類,用于設置對應的數據源名稱:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
|
public class DataSourceContextHolder { private static final ThreadLocal<String> contextHolder = new ThreadLocal<String>(); /** * @Description: 設置數據源類型 * @param dataSourceType 數據庫類型 * @return void * @throws */ public static void setDataSourceType(String dataSourceType) { contextHolder.set(dataSourceType); } /** * @Description: 獲取數據源類型 * @param * @return String * @throws */ public static String getDataSourceType() { return contextHolder.get(); } /** * @Description: 清除數據源類型 * @param * @return void * @throws */ public static void clearDataSourceType() { contextHolder.remove(); } } |
然后在spring中配置,如下:
1
2
3
4
5
6
7
8
9
10
11
12
|
<!-- 編寫spring 配置文件的配置多數源映射關系 --> < 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 > |
這樣配置兩個數據源對應的key分別為testDataSource1和testDataSource2,默認數據庫是testDataSource。
4.完成以上步驟后,如果沒有數據庫的事務管理,已經可以實現數據庫的動態切換了。但是如果涉及到數據庫的事務管理,需要在數據庫事務開啟切換數據庫,
否則數據庫的切換只能在下次數據庫操作時才生效。可以定義一個aop處理類在數據庫事務開啟之前切換數據庫,如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
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.設置數據庫事務切面和切換數據庫切面執行的順序,如下:
1
2
3
4
5
6
|
< 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屬性設置執行的順序,這樣實現了帶事務管理的spring數據庫動態切換。
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持服務器之家。
原文鏈接:http://blog.csdn.net/gaofuqi/article/details/46417281