黄色网页视频 I 影音先锋日日狠狠久久 I 秋霞午夜毛片 I 秋霞一二三区 I 国产成人片无码视频 I 国产 精品 自在自线 I av免费观看网站 I 日本精品久久久久中文字幕5 I 91看视频 I 看全色黄大色黄女片18 I 精品不卡一区 I 亚洲最新精品 I 欧美 激情 在线 I 人妻少妇精品久久 I 国产99视频精品免费专区 I 欧美影院 I 欧美精品在欧美一区二区少妇 I av大片网站 I 国产精品黄色片 I 888久久 I 狠狠干最新 I 看看黄色一级片 I 黄色精品久久 I 三级av在线 I 69色综合 I 国产日韩欧美91 I 亚洲精品偷拍 I 激情小说亚洲图片 I 久久国产视频精品 I 国产综合精品一区二区三区 I 色婷婷国产 I 最新成人av在线 I 国产私拍精品 I 日韩成人影音 I 日日夜夜天天综合

基于 Spring 和 iBATIS 的動態可更新多數據源持

系統 2233 0

前言

我們時常會遇到一些 web 項目,需要從不同的數據源中抓取數據來進行分析,而這些數據源是有可能變化的,需要用戶來進行動態的維護和添加。可是,大多數的 web 程序使用了應用服務器或者容器中間件來管理數據源的生命周期,因此數據源的變化自然不能夠獨立于程序,而需要由專業人士去進行維護,必要時還需要重新發布程序來適應數據源的變化,而且數據源的個數、數據庫的類型也都會有所限制。

那么怎樣才可以突破以上這些局限,徹底實現由用戶遠程對數據源進行維護和管理的需求呢?本文提出了一個有效的解決方案,該方案的大體思路如下:將數據源的配置信息保存在一個地址相對固定的數據庫或本地文件系統中,系統將依據這些配置信息自動生成數據源(每當數據信息發生變化時,系統將重新生成新數據源),然后通過工廠模式的持久層將這些數據源自動分配給對應的類對象使用。如此,只需要一個用戶界面,來對此數據源的配置信息進行管理,就可以實現由用戶自主維護數據源系統的目的了。下文將以一個 Spring+iBATIS 框架的實例,來詳細描述該解決方案的實現。

?

相關技術介紹

iBATIS

Apache iBATIS 是 Clinton Begin 開發,現在由 Apache 基金會支持的用于加快 JDBC 編程的經過泛化的框架,是當前 IT 項目中使用很廣泛的一個半自動 ORM 框架,區別于 Hibernate 之類的全自動框架,iBATIS 對數據庫的操作擁有更加靈活的控制,對于那些經常需要調用本地數據庫函數自定義 SQL 語句,或是喜歡自己優化 SQL 執行效率的開發者來說,iBATIS 是一個非常不錯的選擇。而得到廣泛應用的開源企業架構 Spring Framework,也很好的將 iBATIS 進行了集成,使得 iBATIS 在 Spring 中的使用更加便利、快捷。下面是 iBATIS 的一些關鍵組件:

  • SqlMapClient :是 iBATIS 的重要接口,是線程安全的。這個接口涉及到對 SQL 映射的執行和批處理。
  • Sqlmap - config.xml :是使用 iBATIS 的起點,負責把所有的 SQL 映射文件(sqlmap.xml)組合在一起。該配置文件可以告訴 iBATIS 如何連接數據庫,以及獲取哪些 SQL 映射文件(sqlmap.xml)。
  • sqlmap.xml 包含了我們將要運行的 SQL 語句,被 Sqlmap-config.xml 文件所引用。

基于 Spring 和 iBATIS 的動態可更新多數據源持久層
圖 1.iBATIS 架構圖
?

我們之所以選用 iBATIS 而不是 Hibernate 來作為本解決方案的開發框架,主要是因為相比 Hibernate 來說 iBATIS 更具靈活性,可以更為方便地對其結構進行改寫。尤其是在對不同數據庫結構的封裝方面,iBATIS 更適用于對實現相同邏輯的不同數據庫結構的支持。反觀 Hibernate 則需要對數據庫結構進行封裝,這就意味著對不同的數據庫結構要生成不同的 PO 類,這會使開發工作變得繁瑣。當然用戶也可以選擇使用 Hibernate 來作為框架,其理念是相同的,不同的只是實現手段。

Spring 對 iBATIS 的支持

Spring 通過 DAO 模式,提供了對 iBATIS 的良好支持。

  • SqlMapClient :是 iBATIS 中的主要接口,通過 xml 配置文件可以讓 Spring 容器來管理 SqlMapClient 對象的創建,Spring 提供了 SqlMapClientFactoryBean 來生成該對象。
  • SqlMapClientFactoryBean :SqlMapClientFactoryBean 是由 Spring 所提供的,用來生成 SqlMapClient 對象的一個工廠類。當使用 Spring 配置文件將 SqlMapClientFactoryBean 作為一個 SqlMapClient 的實現類進行注入時,Spring 容器將根據接口里的定義來調用其 getObject 方法,最終返回一個 SqlMapClient 接口的實現類。SqlMapClientFactoryBean 生成的對象擁有兩個重要屬性,configLocation 屬性用來確定 sqlmap-config.xml,dataSource 屬性用來確定數據源。
  • SqlMapClientDaoSupport :Spring 提供的數據庫操作類,應用程序的持久層 DAO 則可以繼承這個類。SqlMapClientDaoSupport 需要 Spring 為其注入 SqlMapClient 接口的實現對象,來確定使用何種數據源和使用何種 sqlmap-config.xml。
?

持久層的架構和設計

如上節所述可知,如果要使傳統的 Spring+iBATIS 框架支持動態的多數據源持久層,則需要對其進行改良。而數據源是由 SqlMapClient 對象的屬性所定義的,所以要想辦法通過變更 SqlMapClient 接口的實現對象來達到目的。Spring 是使用 XML 配置文件來存儲 SqlMapClient 對象的信息,因此只需要能夠根據數據源配置信息來動態生成該 XML 配置文件,來實現對 SqlMapClient 接口的動態注入即可。

?

?

?

?

持久層架構的具體處理流程如上圖所示:

1.創建配置文件生成類 SqlMapClientFactory,當應用服務器啟動時,Spring 框架將啟動 SqlMapClientFactory 類的 init 方法(每當數據源配置信息發生變化時也重新啟動此方法),該方法將讀取數據庫或本地文件系統中存儲的數據源配置信息,然后動態的生成 Spring XML 配置文件。在此 XML 配置文件中,根據不同的數據源定義了很多不同的 SqlMapClient 對象,并定義了其相對應的數據源和 sqlmap-config 文件。

2.創建 SqlMapClient 接口的實現類 RoutingSqlMapClient,并通過 Spring 將生成的所有 SqlMapClient 對象以 Map 的結構形式注入到 RoutingSqlMapClient 中,當其被調用時將根據要求使用相應的 SqlMapClient 實現對象來對 RoutingSqlMapClient 的方法進行重寫。

3.將 RoutingSqlMapClient 注入到所有繼承了 SqlMapClientDaoSupport 的 DAO 實現類中,DAO 將根據實際需求決定使用哪個數據源。

?

持久層的具體實現

使用 SqlMapClientFactory 類生成 XML 配置文件

如上文的描述,第一步應該創建 SqlMapClientFactory 類,并創建一個用來生成 SqlMapClient 的 XML 配置文件的方法。然后配置 Spring,使其能在程序啟動時自動調用 SqlMapClient 的該方法。該方法要從本地文件系統或地址相對固定的數據庫系統中讀取數據源配置信息,SqlMapClientFactory 所讀取的數據源配置信息的主要字段如下:

注:<hostname> 是數據庫所在的服務器地址,<portNum> 是數據庫所用服務端口號,<databaseName> 是數據庫名稱,<userName> 是數據庫用戶名,<password> 是該用戶的密碼


表 1 數據源配置信息

ID Name Connection User Password DBType
00001 PROJECTA jdbc:db2:// <hostname> : <portNum> / <databaseName> <userName> <password> DB2
00002 PROJECTB jdbc:microsoft:sqlserver:// <hostname> :
<portNum>
;DatabaseName= <databaseName>
<userName> <password> sqlserver
00003 PROJECTC jdbc:db2:// <hostname> : <portNum> / <databaseName> <userName> <password> DB2
00004 PROJECTD jdbc:db2:// <hostname> : <portNum> / <databaseName> <userName> <password> DB2

?

SqlMapClientFactory 將根據這些配置信息生成相應的 SqlMapClient 對象的 XML 配置文件。下面詳細介紹一下該 XML 配置文件的主要構成。

1,根據數據源配置信息的 ID 和 Name,生成所有 SqlMapClient 接口實現對象的 Map 列表。


清單 1. routingSqlMapClient 配置

              				 
 <bean id="routingSqlMapClient" class="com.ibm.mbps.tsd.dao.RoutingSqlMapClient"> 
  <property name="targetSqlMapClients"> 
 <map key-type="java.lang.String"> 
 <entry key="PROJECTA" value-ref="sqlmapClient_00001"/> 
 <entry key="PROJECTB" value-ref="sqlmapClient_00002"/> 
 <entry key="PROJECTC" value-ref="sqlmapClient_00003"/> 
 <entry key="PROJECTD" value-ref="sqlmapClient_00004"/> 
		……
    </map> 
 </property> 
 </bean> 

            

?

2,為每個 SqlMapClient 接口實現對象創建數據源,數據源根據上文的配置信息生成。


清單 2. data source 配置示例

              				 
 <bean id="datasource_00001" class="org.apache.commons.dbcp.BasicDataSource"> 
 <property name="driverClassName"> 
    <value>com.ibm.db2.jcc.DB2Driver</value> 
  </property> 
  <property name="url"> 
    <value> jdbc:db2://hostname:portNum/databaseName</value> 
  </property> 
  <property name="username"> 
    <Value>userName</value> 
  </property> 
  <property name="password"> 
    <value>password</value> 
 </property> 
 </bean> 

            

?

3,為每個 SqlMapClient 對象注入數據源和 sqlmap-config 配置文件,應該注意的是該 sqlmap-config 配置文件是針對某一類數據源的,比如多個數據源的數據庫類型和數據庫內容都相同,那么就應該使用同一張配置文件。


清單 3. SqlMapClient 對象配置示例

              				 
 <bean id=" sqlmapClient_00001" class="org.springframework.orm.ibatis.SqlMapClient 
 FactoryBean"> 
 <property name="configLocation" value="classpath:/sqlmap/db2/sql-map-config.xml"/> 
    <property name="dataSource"> 
      <ref local=" datasource_00001"/> 
    </property> 
 </bean> 

            

?

重寫 SqlMapClient 接口的實現類 RoutingSqlMapClient

生成了 SqlMapClient 對象后,我們還要創建一個 RoutingSqlMapClient 的實現類用來重寫相應的 SqlMapClient 接口方法。RoutingSqlMapClient 將創建一個 Map 變量去承接上文生成的 SqlMapClient 實現對象的 Map 列表,然后根據關鍵字來判斷用哪個實現對象來動態的重寫 RoutingSqlMapClient 類。RoutingSqlMapClient 使用變量 targetSqlMapClients 來接收 SqlMapClient 對象列表。


清單 4. RoutingSqlMapClient 類的代碼片段

              				 
 public class RoutingSqlMapClient implements SqlMapClient { 
 private Map<String, SqlMapClient> targetSqlMapClients; 
 public void flushDataCache() 
 { 
 targetSqlMapClients.get(getDSType()).flushDataCache(); 
 } 
 public SqlMapSession getSession() 
 { 
 return targetSqlMapClients.get(getDSType()).getSession(); 
 } 
 public int delete(String id, Object parameterObject) throws SQLException 
 { 
 return targetSqlMapClients.get(getDSType()).delete(id,parameterObject); 
 } 
 public Object insert(String id, Object parameterObject) throws SQLException 
 { 
 return targetSqlMapClients.get(getDSType()).insert(id,parameterObject); 
 } 
 public List queryForList(String id, Object parameterObject) throws SQLException { 
 return targetSqlMapClients.get(getDSType()).queryForList(id,parameterObject); 
 } 
……
 } 

            

?

創建繼承 SqlMapClientDaoSupport 的 DAO 類

我們選擇使用 RoutingSqlMapClient 重寫 SqlMapClient 的實現方法,而不是將 SqlMapClient 實現對象直接注入到對應 DAO 中的原因是:一個 DAO 類有可能對應多個數據源,如果將只包含一個數據源的 SqlMapClient 實現對象直接注入 DAO,那將嚴重限制 DAO 的可重用性。因此我們將整個 SqlMapClient 實現對象的列表裝載入 RoutingSqlMapClient 類,在邏輯層定義使用哪一個 SqlMapClient 對象對 RoutingSqlMapClient 進行重寫,持久層的 DAO 架構如下圖所示:


圖 3. 持久層 DAO 架構圖( 查看大圖
基于 Spring 和 iBATIS 的動態可更新多數據源持久層 ?

DAO 實體類繼承 SqlMapClientDaoSupport 并實現相應不同的接口。如圖所示,不同的接口對應不同的上層邏輯,而實現其邏輯的 DAO 實現類引用了不同的數據源和 sqlmap-config.xml,這些數據源和 XML 定義在 SqlMapClient 對象內,當我們調用持久層 DAO 類對數據庫進行操作時需要先調用 RoutingSqlMapClient 內的 setDSType() 方法來確定使用哪個數據源,并使用對應的 SqlMapClient 實現對象對 RoutingSqlMapClient 進行重寫,這樣就可以把對應此數據源的 SqlMapClient 以 RoutingSqlMapClient 對象的形式傳入到 DAO 內,實現多數據源并存的結構了。

支持動態更新的多數據源持久層開發完畢后,還應該為用戶開發一套 UI 組件來使用戶能夠對數據源信息進行更新和維護。而每次用戶更新完畢都要調用 SqlMapClientFactory 類的 init 方法,來重新生成 SqlMapClient 的 XML 配置文件,這樣就可以不重新啟動服務器而實現數據源的動態更新和添加了。

?

總結

本文描述了,可動態更新的多數據源持久層系統的一種實現方式,對于開發類似項目的開發者有一定的借鑒作用。但是由于本文的主要目的是闡述一種理念方法而不是具體實現,所以一些相關技術及具體實現沒有寫出,但開發者可以根據本文的思路選用自己喜歡的方式來進行實現,此外對于一些名詞和 iBATIS 及 Spring 的功能沒有予以詳細介紹,建議對 iBATIS 架構不熟的讀者能夠自行參考其它教程。本文選用 Spring+iBATIS 框架僅作為示例,但僅僅是建議使用,不對使用結果和效果做任何保證。(本文內容僅代表作者個人觀點)

基于 Spring 和 iBATIS 的動態可更新多數據源持久層


更多文章、技術交流、商務合作、聯系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號聯系: 360901061

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對您有幫助就好】

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長會非常 感謝您的哦!!!

發表我的評論
最新評論 總共0條評論