首頁  >  文章  >  Java  >  Spring實作動態切換多資料來源的解決方案

Spring實作動態切換多資料來源的解決方案

高洛峰
高洛峰原創
2017-01-24 10:44:201704瀏覽

前言

Spring動態配置多重資料來源,即在大型應用中對資料進行切分,並且採用多個資料庫執行個體進行管理,這樣可以有效提高系統的水平伸縮性。而這樣的方案就會不同於常見的單一資料實例的方案,這就要程式在運行時根據當時的請求及系統狀態來動態的決定將資料儲存在哪個資料庫實例中,以及從哪個資料庫提取資料。

Spring2.x以後的版本中採用Proxy模式,就是我們在方案中實作一個虛擬的資料來源,並且用它來封裝資料來源選擇邏輯,這樣就可以有效地將資料來源選擇邏輯從Client中分離出來。 Client提供選擇所需的上下文(因為這是Client所知道的),由虛擬的DataSource根據Client提供的上下文來實現資料來源的選擇。

實作

具體的實作就是,虛擬的DataSource只需繼承AbstractRoutingDataSource實作determineCurrentLookupKey()在其中封裝資料來源的選擇邏輯。

一、動態配置多重資料來源

1. 資料來源的名稱常數類別:

/**
 * 动态配置多数据源
 * 数据源的名称常量类
 * @author LONGHUI_LUO
 *
 */
public class DataSourceConst {
 public static final String TEST="test";
 public static final String USER="User";
}

   


2. 建立一個情境來源改變環境的資料來源的主要獲得和設定資料來源,主要獲得和設定上下文環境的一個類別:

/**
 * 获得和设置上下文环境 主要负责改变上下文数据源的名称
 *
 * @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,一般是返回字符串:

/**
 * 建立动态数据源
 *
 * @author LONGHUI_LUO
 *
 */
public class DynamicDataSource extends AbstractRoutingDataSource {
  
 protected Object determineCurrentLookupKey() {
 // 在进行DAO操作前,通过上下文环境变量,获得数据源的类型
 return DataSourceContextHolder.getDataSourceType();
 }
  
}

   


4. 編寫spring的設定檔配置多個資料來源

  <!-- 数据源相同的内容 -->
<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設定檔設定多重資料來源對應關係

<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>
 目標資料來源,中的key-type必須要和靜態鍵值對照類別DataSourceConst中的值的類型相同;中key的值必須要和靜態鍵值對照類別中的值相同,如果有多個值,可以配置多個標籤。第二個property屬性配置預設的資料來源。

動態切換是資料來源

DataSourceContextHolder.setDataSourceType(DataSourceConst.TEST);

   

該方案的優點

首先,這個方案完全是在spring的框架下解決的,資料來源仍然配置在springsion的設定檔中仍然配置在springsion它的dataSource屬性,它甚至不知道dataSource的改變。唯一不同的是在真正的dataSource與sessionFactory之間增加了一個MultiDataSource。


其次,實現簡單,易於維護。這個方案雖然我說了這麼多東西,其實都是分析,真正需要我們寫的程式碼就只有MultiDataSource、SpObserver兩個類別。 MultiDataSource類別真正要寫的只有getDataSource()和getDataSource(sp)兩個方法,而SpObserver類別更簡單了。實現越簡單,出錯的可能越小,維護性就越高。

最後,這個方案可以讓單一資料來源與多重資料來源相容。這個方案完全不影響BUS和DAO的編寫。如果我們的專案在開始之初是單一資料來源的情況下開發,隨著專案的進行,需要變更為多資料來源,則只需要修改spring配置,並少量修改MVC層以便在請求中寫入所需的資料來源名,變更就完成了。如果我們的專案希望改回單一資料來源,則只需要簡單修改設定檔。這樣,為我們的專案將增加更多的彈性。

該方案的缺點

沒有能夠解決多用戶訪問單例“sessionFactory”時共享“dataSource”變量,導致產生爭搶“dataSource”的結果,本質類似於操作系統中的“生產者消費者”問題。因此當多用戶存取時,多資料來源可能會導致系統效能下降的後果。


總結

以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或工作能帶來一定的幫助,如果有疑問大家可以留言交流。

更多Spring實現動態切換多資料來源的解決方案相關文章請關注PHP中文網!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn