聊聊Java項(xiàng)目的動(dòng)態(tài)多數(shù)據(jù)源配置

? ? ? ?在我們的項(xiàng)目中遇到這樣一個(gè)問題:我們的項(xiàng)目需要連接多個(gè)數(shù)據(jù)庫(kù),而且不同的客戶在每次訪問中根據(jù)需要會(huì)去訪問不同的數(shù)據(jù)庫(kù)。所以就采用了多數(shù)據(jù)源的方式(可以根據(jù)客戶的需求去連接客戶所需要的真正的數(shù)據(jù)源,即提供動(dòng)態(tài)切換數(shù)據(jù)源的功能)。

? ? ? ?多數(shù)據(jù)源配置是怎么個(gè)配置法,其中用到了些什么技術(shù),想必大家都會(huì)有這個(gè)疑問,下面將逐一介紹。

? ? ? ?大概思路是這樣的:在登錄頁(yè)面放置一個(gè)下拉選擇列表(使用的Bootstrap框架的dropdown-menu,不懂的可以百度一下特別好用),下拉列表在加載以前是從后臺(tái)讀取的一個(gè)包含了多個(gè)數(shù)據(jù)庫(kù)信息的Json文件,前臺(tái)通過js循環(huán)渲染出來。另外有一個(gè)子頁(yè)面可以創(chuàng)建新的數(shù)據(jù)庫(kù)保存到剛才的那個(gè)Json文件中。

關(guān)鍵點(diǎn)來了,最主要的是登錄的時(shí)候選了不同的數(shù)據(jù)庫(kù),后臺(tái)是怎么知道并且登錄成功的。

寫一個(gè)DBContextHolder類放一個(gè)多線程的變量記錄當(dāng)前數(shù)據(jù)源,具體實(shí)現(xiàn)類繼承AbstractRoutingDataSource類并且重寫方法determineCurrentLookupKey獲取當(dāng)前數(shù)據(jù)源,如果當(dāng)前數(shù)據(jù)源不存在就新建并且要通知spring容器。

具體代碼如下:

1.datasource.xml配置文件內(nèi)容:

<bean id="datasource"? class="xxxxxxxxxxx.DynamicDataSource">

? ? <property name="targetDataSources"> ? <map></map> ?</property>

</bean>

2.DynamicDataSource.class

package ? ?com.core;

import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;

public ?class ?DynamicDataSource ? ?extends ? ?AbstractRoutingDataSource{

? ? /*datasource.xml配置文件中配置數(shù)據(jù)源為此類*/

? ? ?public DynamicDataSource(){ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? /*默認(rèn)數(shù)據(jù)源*/

? ? ? ? ? ? ? ? HashMapmap_1 = new HashMap();

? ? ? ? ? ? ? ? ?map_1.put("DRIVER_CLASS", "com.mysql.jdbc.Driver");

? ? ? ? ? ? ? ? map_1.put("dbUrl", "jdbc:mysql://127.0.0.1:3306/ifms? ? ? ? ? ? ? ? ? ? ? ? useUnicode=true&characterEncoding=utf8&allowMultiQueries=true&autoReconnect=true");

? ? ? ? ? ? ? ? ? map_1.put("dbUserName", "root");

? ? ? ? ? ? ? ? ?map_1.put("dbPassword", "123456");

? ? ? ? ? ? ? ? dbMap.put("db0", map_1);

}

? ? @Override

? ? protected ? Object?determineCurrentLookupKey()?{ ? ? ? ? ? /*得到當(dāng)前數(shù)據(jù)源*/

? ? ? ? ? return ? DatabaseContextHolder.getCustomerType();

? ? }

? ? public void setTargetDataSources(MaptargetDataSources) {

? ? ? ? ? ?this._targetDataSources = targetDataSources;

? ? ? ? ? ?super.setTargetDataSources(this._targetDataSources);

? ? ? ? ? ?super.afterPropertiesSet();//當(dāng)我們添加數(shù)據(jù)庫(kù),切換了數(shù)據(jù)源,要通知當(dāng)前spring容器

? ?}

? ? public void addTargetDataSource(String key, BasicDataSource dataSource) {

? ? ? ? ? ?this._targetDataSources.put(key, dataSource);

? ? ? ? ? ?this.setTargetDataSources(this._targetDataSources);

? ?}

? ?public BasicDataSource createDataSource(String driverClassName, String url,

? ? ? ? ? String username, String password) {

? ? ? ? ? BasicDataSource dataSource = new BasicDataSource();

? ? ? ? ? dataSource.setDriverClassName(driverClassName);

? ? ? ? ? dataSource.setUrl(url);

? ? ? ? ? dataSource.setUsername(username);

? ? ? ? ?dataSource.setPassword(password);

? ? ? ? ? dataSource.setTestWhileIdle(true);

? ? ? ? ? return dataSource;

?}

/**

* @param serverId

* @describe 數(shù)據(jù)源存在時(shí)不做處理,不存在時(shí)創(chuàng)建新的數(shù)據(jù)源鏈接,并將新數(shù)據(jù)鏈接添加至緩存

*/

? ? ?public void selectDataSource(String serverId) {

? ? ? ? ? ?Object sid = DBContextHolder.getCustomerType();? ? ? ? ?

? ? ? ? ? ?Object obj = this._targetDataSources.get(serverId);

? ? ? ? ? ? if (obj != null && sid.equals(serverId + "")) {

? ? ? ? ? ? ? ? ? ?return;

? ? ? ? ? ? ?} else {

? ? ? ? ? ? ?System.out.println("---數(shù)據(jù)源不存在,創(chuàng)建數(shù)據(jù)源");

? ? ? ? ? ? ? BasicDataSource dataSource = this.getDataSource(serverId); ?//判斷當(dāng)前數(shù)據(jù)源是否存在

? ? ? ? ? ? ?if (null != dataSource)

? ? ? ? ? ? ? ? ? ? ?this.setDataSource(serverId, dataSource); ? ? ? ? ? ? ? ? ? ? ? ?//設(shè)置當(dāng)前數(shù)據(jù)源

? ? ? ? ? ? ?}

? ? ? ?}

? ? ?public void setDataSource(String serverId, BasicDataSource dataSource) {

? ? ? ? ? this.addTargetDataSource(serverId, dataSource);

? ? ? ? ? DBContextHolder.setCustomerType(serverId);

? ? ?}

}

3.DBContextHolder.class

package ? com.core;

public? class? DBContextHolder{

private ? static ? final ? Thread ? Local?contextHolder?=newThreadLocal();

? ?public ? static ? void ? setCustomerType(String?customerType)?{

? ? ? contextHolder.set(customerType);

? ?}

? ? public ? static ? String?getCustomerType()?{

? ? ? ? return ? contextHolder.get();

? ? ?}

? ?public ? static ? void ? clearCustomerType()?{

? ? ? ?contextHolder.remove();

? ?}

}

? ? ? 其中遇到個(gè)問題,如果將數(shù)據(jù)源變量定義為多線程的時(shí)候,如果前臺(tái)頁(yè)面另起一個(gè)線程并且中途出現(xiàn)異常之后會(huì)獲取不到當(dāng)前數(shù)據(jù)源。所以暫時(shí)改為了一個(gè)靜態(tài)變量但是只能支持單線程。如果有一臺(tái)電腦正用著A數(shù)據(jù)庫(kù),另外一臺(tái)電腦突然用B數(shù)據(jù)庫(kù)登錄,那原來那個(gè)的數(shù)據(jù)庫(kù)也會(huì)變成A。目前還沒有找到好的方法解決這個(gè)問題,找到了會(huì)繼續(xù)更新。如果誰(shuí)有比較好的方法也可以告訴我,灰常感激?。。。。。。。。。。。。。。。。。?/p>

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,551評(píng)論 19 139
  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語(yǔ)法,類相關(guān)的語(yǔ)法,內(nèi)部類的語(yǔ)法,繼承相關(guān)的語(yǔ)法,異常的語(yǔ)法,線程的語(yǔ)...
    子非魚_t_閱讀 34,670評(píng)論 18 399
  • 一. Java基礎(chǔ)部分.................................................
    wy_sure閱讀 4,011評(píng)論 0 11
  • 通過整合藝龍和去哪兒,攜程在表面上完成了在線預(yù)訂酒店和機(jī)票業(yè)務(wù)的壟斷,在線旅游(OTA)整合的大戲表面上已經(jīng)落幕。...
    jackiefang閱讀 333評(píng)論 0 1
  • 不要問我你離開了我怎么過 像以前一樣過 一日三餐不能少,八個(gè)小時(shí)的睡眠時(shí)間也不能少
    九木先生閱讀 187評(píng)論 0 0

友情鏈接更多精彩內(nèi)容