前言
Spring動態配置多數據源,即在大型應用中對數據進行切分,并且采用多個數據庫實例進行管理,這樣可以有效提高系統的水平伸縮性。而這樣的方案就會不同于常見的單一數據實例的方案,這就要程序在運行時根據當時的請求及系統狀態來動態的決定將數據存儲在哪個數據庫實例中,以及從哪個數據庫提取數據。
Spring2.x以后的版本中采用Proxy模式,就是我們在方案中實現一個虛擬的數據源,并且用它來封裝數據源選擇邏輯,這樣就可以有效地將數據源選擇邏輯從Client中分離出來。Client提供選擇所需的上下文(因為這是Client所知道的),由虛擬的DataSource根據Client提供的上下文來實現數據源的選擇。
實現
具體的實現就是,虛擬的DataSource僅需繼承AbstractRoutingDataSource實現determineCurrentLookupKey()
在其中封裝數據源的選擇邏輯。
一、動態配置多數據源
1. 數據源的名稱常量類:
1
2
3
4
5
6
7
8
9
10
|
/** * 動態配置多數據源 * 數據源的名稱常量類 * @author LONGHUI_LUO * */ public class DataSourceConst { public static final String TEST= "test" ; public static final String USER= "User" ; } |
2. 建立一個獲得和設置上下文環境的類,主要負責改變上下文數據源的名稱:
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
|
/** * 獲得和設置上下文環境 主要負責改變上下文數據源的名稱 * * @author LONGHUI_LUO * */ public class DataSourceContextHolder { private static final ThreadLocal contextHolder = new ThreadLocal(); // 線程本地環境 // 設置數據源類型 public static void setDataSourceType(String dataSourceType) { contextHolder.set(dataSourceType); } // 獲取數據源類型 public static String getDataSourceType() { return (String) contextHolder.get(); } // 清除數據源類型 public static void clearDataSourceType() { contextHolder.remove(); } } |
3. 建立動態數據源類,注意,這個類必須繼承AbstractRoutingDataSource,且實現方法determineCurrentLookupKey,該方法返回一個Object,一般是返回字符串:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
/** * 建立動態數據源 * * @author LONGHUI_LUO * */ public class DynamicDataSource extends AbstractRoutingDataSource { protected Object determineCurrentLookupKey() { // 在進行DAO操作前,通過上下文環境變量,獲得數據源的類型 return DataSourceContextHolder.getDataSourceType(); } } |
4. 編寫spring的配置文件配置多個數據源
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
<!-- 數據源相同的內容 --> <bean id= "parentDataSource" class = "org.apache.commons.dbcp.BasicDataSource" destroy-method= "close" > <property name= "driverClassName" value= "com.microsoft.sqlserver.jdbc.SQLServerDriver" /> <property name= "username" value= "sa" /> <property name= "password" value= "net2com" /> </bean> <!-- start以下配置各個數據源的特性 --> <bean parent= "parentDataSource" id= "testDataSource" > <propertynamepropertyname= "url" value= "jdbc:sqlserver://localhost:1433;databaseName=test" /> </bean> <bean parent= "parentDataSource" id= "UserDataSource" > <property name= "url" value= "jdbc:sqlserver://localhost:1433;databaseName=User" /> </bean> <!-- end 配置各個數據源的特性 --> |
5. 編寫spring配置文件配置多數據源映射關系
1
2
3
4
5
6
7
8
9
|
<bean class = "com.xxxx.datasouce.DynamicDataSource" id= "dataSource" > <property name= "targetDataSources" > <map key-type= "java.lang.String" > <entry value-ref= "testDataSource" key= "test" ></entry> <entry value-ref= "UserDataSource" key= "User" ></entry> </map> </property> <property name= "defaultTargetDataSource" ref= "testDataSource" ></property> </bean> |
在這個配置中第一個property屬性配置目標數據源,<map key-type="java.lang.String">
中的key-type必須要和靜態鍵值對照類DataSourceConst中的值的類型相 同;<entry key="User" value-ref="userDataSource"/>
中key的值必須要和靜態鍵值對照類中的值相同,如果有多個值,可以配置多個< entry>標簽。第二個property屬性配置默認的數據源。
動態切換是數據源
1
|
DataSourceContextHolder.setDataSourceType(DataSourceConst.TEST); |
該方案的優勢
首先,這個方案完全是在spring的框架下解決的,數據源依然配置在spring的配置文件中,sessionFactory依然去配置它的dataSource屬性,它甚至都不知道dataSource的改變。唯一不同的是在真正的dataSource與sessionFactory之間增加了一個MultiDataSource。
其次,實現簡單,易于維護。這個方案雖然我說了這么多東西,其實都是分析,真正需要我們寫的代碼就只有MultiDataSource、SpObserver兩個類。MultiDataSource類真正要寫的只有getDataSource()
和getDataSource(sp)
兩個方法,而SpObserver類更簡單了。實現越簡單,出錯的可能就越小,維護性就越高。
最后,這個方案可以使單數據源與多數據源兼容。這個方案完全不影響BUS和DAO的編寫。如果我們的項目在開始之初是單數據源的情況下開發,隨著項目的進行,需要變更為多數據源,則只需要修改spring配置,并少量修改MVC層以便在請求中寫入需要的數據源名,變更就完成了。如果我們的項目希望改回單數據源,則只需要簡單修改配置文件。這樣,為我們的項目將增加更多的彈性。
該方案的缺點
沒有能夠解決多用戶訪問單例“sessionFactory”時共享“dataSource”變量,導致產生爭搶“dataSource”的結果,本質類似于操作系統中的“生產者消費者”問題。因此當多用戶訪問時,多數據源可能會導致系統性能下降的后果。
總結
以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作能帶來一定的幫助,如果有疑問大家可以留言交流。
原文鏈接:http://www.cnblogs.com/zengda/p/4500684.html?utm_source=tuicool