需求很簡單,相同的操作,比如表結構完全相同,程序也完全相同,但需要根據某些條件,分別向不同的schema做操作。
比如,如果當前處理的是A公司,那麼向SchemaA 裡面保存數據,如果當前處理的是B公司的,則向SchemaB裡面保存數據。
其實就是一套程序,實現後台的動態切換。
我這裡提供幾種方法,大家自己根據情況考慮,都能實現,注意是實現,不一定適合於正式應用。
方法一:
在Hibernate裡面,有一個配置參數,比如下面這個帶Schema配置的映射
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!--
Mapping file autogenerated by MyEclipse Persistence Tools
-->
<hibernate-mapping>
<class name="com.csc.poimanager.dao.Poi" table="POI" schema="P_BEIJING">
<id name="poiId" type="java.lang.Long">
<column name="POI_ID" precision="10" scale="0" />
<generator class="increment" />
</id>
<property name="cnName" type="java.lang.String">
<column name="CN_NAME" length="1000" />
</property>
</class>
</hibernate-mapping>
其中的schema="P_BEIJING"將 Schema寫死了。
我們可以不寫這部分,而是使用系統的配置參數
<property name="hibernate.default_schema">POI_BEIJING</property>
這樣的話,我們的映射文件就變成了
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!--
Mapping file autogenerated by MyEclipse Persistence Tools
-->
<hibernate-mapping>
<class name="com.csc.poimanager.dao.Poi" table="POI"">
<id name="poiId" type="java.lang.Long">
<column name="POI_ID" precision="10" scale="0" />
<generator class="increment" />
</id>
<property name="cnName" type="java.lang.String">
<column name="CN_NAME" length="1000" />
</property>
</class>
</hibernate-mapping>
在調用的時候,動態的指定Schema的參數就行了,比如
public static SessionFactory rebuildSessionFactoryForChangeSchema(String newSchema){
try {
Properties p = configuration.getProperties();
System.out.println("---" + p);
p.put("hibernate.default_schema", newSchema);
sessionFactory = configuration.buildSessionFactory();
System.out.println(" change schema successfully ......... ");
return sessionFactory;
} catch (Exception e) {
System.err
.println("%%%% rebuild session factory failed for changing schema %%%%");
e.printStackTrace();
return null;
}
}
這個方法能實現切換,但是我們必須每次都返回一個SessionFactory, 否則在並發的時候就會出問題。因為hibernate.default_schema系統只有一個。
方法二:
使用多重配置,比如針對天津和北京,我們分別編寫對應的映射文件
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!--
Mapping file autogenerated by MyEclipse Persistence Tools
-->
<hibernate-mapping>
<class name="com.csc.poimanager.dao.Poi" table="POI" id="P_BEIJING" schema="P_BEIJING">
<id name="poiId" type="java.lang.Long">
<column name="POI_ID" precision="10" scale="0" />
<generator class="increment" />
</id>
<property name="cnName" type="java.lang.String">
<column name="CN_NAME" length="1000" />
</property>
</class>
<class name="com.csc.poimanager.dao.Poi" id="P_TIANJIN" table="POI" schema="P_TIANJIN">
<id name="poiId" type="java.lang.Long">
<column name="POI_ID" precision="10" scale="0" />
<generator class="increment" />
</id>
<property name="cnName" type="java.lang.String">
<column name="CN_NAME" length="1000" />
</property>
</class>
</hibernate-mapping>
配置文件除了SCHEMA和ID不同外,其它的完全相同,那麼如何使用呢?
sessionFactory.getBean("P"+placeName);
這樣就可以實現動態調用了。
至於placeName,可以通過前台調用程序傳遞過來,也可以放到ThreadLocal裡面,後者更具有通用性,而且對以前的程序修改量最少,因為只需要寫一個getPlaceName()得方法就行了。
方法3:
修改數據庫的連接屬性,將以前指向SchemaA的改成指向SchemaB,這需要一些高權限的賬號做這些事情。
其實,還有一個更簡單的方法,那就是自己繼承一個DataSource,然後在方法裡面,根據ThreadLocal的參數,返回不同的數據連接。比如如果是BEIGJING,則返回 BeiJingDatasource的連接,如果是TIANJIN,則返回TianJinDatasource的連接。
系統在使用時,肯定會從DataSource裡面獲取連接,我們在內部做了分配,自然前台運行結果也就分配開了。
提示:在你的DataSource裡面可以包含Map<String,DataSource>這樣的結構,來做內部的轉發。
個人總結:
第一種方法只適合於單機,單線程使用。
第二個方法,相對技術難度低一點,單配置起來要寫多份,維護比較麻煩
第三個方法,技術難度高,單維護起來簡單
我個人當然是用第三個方法了,很有趣。