實現Myibatis動態sql跨數據庫的處理
Spring動態配置多數據源,即在大型應用中對數據進行切分,並且采用多個數據庫實例進行管理,這樣可以有效提高系統的水平伸縮性。而這樣的方案就會不 同於常見的單一數據實例的方案,這就要程序在運行時根據當時的請求及系統狀態來動態的決定將數據存儲在哪個數據庫實例中,以及從哪個數據庫提取數據。
Spring配置多數據源的方式和具體使用過程。
Spring對於多數據源,以數據庫表為參照,大體上可以分成兩大類情況:
一是,表級上的跨數據庫。即,對於不同的數據庫卻有相同的表(表名和表結構完全相同)。
二是,非表級上的跨數據庫。即,多個數據源不存在相同的表。
Spring2.x的版本中采用Proxy模式,就是我們在方案中實現一個虛擬的數據源,並且 用它來封裝數據源選擇邏輯,這樣就可以有效地將數據源選擇邏輯從Client中分離出來。Client提供選擇所需的上下文(因為這是Client所知道 的),由虛擬的DataSource根據Client提供的上下文來實現數據源的選擇。
具體的實現就是,虛擬的DataSource僅需繼承AbstractRoutingDataSource實現determineCurrentLookupKey()在其中封裝數據源的選擇邏輯。
一、動態配置多數據源
1. 數據源的名稱常量類:
package com.hope.common.data;
public class DataSourceConst {
public static final String MANAGER = "MANAGER";
public static final String STMT = "STMT";
public static final String NODB = "NODB";
}
2. 建立一個獲得和設置上下文環境的類,主要負責改變上下文數據源的名稱:
public class DataSourceHandle {
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,一般是返回字符串:
package com.hope.datasource;
public class DynamicDataSource extends AbstractRoutingDataSource {
public DynamicDataSource(){
}
@Override
protected Object determineCurrentLookupKey() {
// 在進行DAO操作前,通過上下文環境變量,獲得數據源的類型
return DataSourceHandle.getDataSourceType();
}
} 4. 編寫spring的配置文件配置多個數據源
<!-- spring配置多數據源 -->
<bean id="parentDataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="net.sourceforge.jtds.jdbc.Driver"></property>
<property name="username" value="sa"></property>
<property name="password" value="sa</property>
</bean>
<!-- 以下是配置各個數據庫的特性 -->
<!-- 數據庫 -->
<bean id="NODBDataSource" parent="parentDataSource">
<property name="url" value="jdbc:jtds:sqlserver://localhost:1433/" />
</bean>
<bean id="managerDataSource" parent="parentDataSource">
<property name="url"
value="jdbc:jtds:sqlserver://localhost:1433/test1
</bean>
<bean id="statDataSource" parent="parentDataSource">
<property name="url" value="jdbc:jtds:sqlserver://localhost:1433/test2
</bean>
<bean id="dataSource" class="com.hope.common.data.DynamicDataSource">
<property name="targetDataSources">
<map key-type="java.lang.String">
<entry value-ref="managerDataSource" key="MANAGER"></entry>
<entry value-ref="statDataSource" key="STMT"></entry>
<entry value-ref="NODBDataSource" key="NODB"></entry>
</map>
</property>
<property name="defaultTargetDataSource" ref="managerDataSource"></property>
</bean>
5. ibatis 相關sql
<select id="selectDBDictionary" resultMap="BaseResultMap" parameterType="java.lang.Integer" >
select a.id,a.parentid,a.cname,a.priority,a.ifactive from hopetas_manager.dbo.dictionary a inner join zj.dbo.dictionary b on a.id=b.id where a.parentid= #{id,jdbcType=INTEGER}
</select>
6.程序調用: 在DAO操作前處理set setDataSourceType 的值
// 利用遞歸來處理字段
public void getDict0(Eement element, Integer id,Integer j) {
// 設置數據源
DataSourceHandle.setDataSourceType(DataSourceConst.NODB);
ArrayList list = (ArrayList) this.dictMapper
.selectDBDictionary(id);
String str = "dir";
j++;
if (list.size() != 0 && list != null) {
for (Iterator iter = list.iterator(); iter.hasNext();) {
Dictionary dict = (Dictionary) iter.next();
Element el = element.addElement(str+j);
Element prop1 = el.addAttribute("id", dict.getId().toString());
Element prop2 = el.addAttribute("name", dict.getCname()
.toString());
getDict0(el, dict.getId(),j);
}
}
}