激情久久久_欧美视频区_成人av免费_不卡视频一二三区_欧美精品在欧美一区二区少妇_欧美一区二区三区的

服務(wù)器之家:專注于服務(wù)器技術(shù)及軟件下載分享
分類導(dǎo)航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術(shù)|正則表達(dá)式|C/C++|IOS|C#|Swift|Android|JavaScript|易語(yǔ)言|

服務(wù)器之家 - 編程語(yǔ)言 - Java教程 - spring實(shí)現(xiàn)動(dòng)態(tài)切換、添加數(shù)據(jù)源及源碼分析

spring實(shí)現(xiàn)動(dòng)態(tài)切換、添加數(shù)據(jù)源及源碼分析

2021-05-31 13:37殷天文 Java教程

這篇文章主要給大家介紹了關(guān)于spring實(shí)現(xiàn)動(dòng)態(tài)切換、添加數(shù)據(jù)源及源碼分析的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧

前言

對(duì)于數(shù)據(jù)量在1千萬(wàn),單個(gè)mysql數(shù)據(jù)庫(kù)就可以支持,但是如果數(shù)據(jù)量大于這個(gè)數(shù)的時(shí)候,例如1億,那么查詢的性能就會(huì)很低。此時(shí)需要對(duì)數(shù)據(jù)庫(kù)做水平切分,常見(jiàn)的做法是按照用戶的賬號(hào)進(jìn)行hash,然后選擇對(duì)應(yīng)的數(shù)據(jù)庫(kù)。

最近公司項(xiàng)目需求,由于要兼容老系統(tǒng)的數(shù)據(jù)庫(kù)結(jié)構(gòu),需要搭建一個(gè) 可以動(dòng)態(tài)切換、添加數(shù)據(jù)源的后端服務(wù)。

參考了過(guò)去的項(xiàng)目,通過(guò)配置多個(gè)sqlsessionfactory 來(lái)實(shí)現(xiàn)多數(shù)據(jù)源,這么做的話,未免過(guò)于笨重,而且無(wú)法實(shí)現(xiàn)動(dòng)態(tài)添加數(shù)據(jù)源這個(gè)需求

spring實(shí)現(xiàn)動(dòng)態(tài)切換、添加數(shù)據(jù)源及源碼分析

通過(guò) spring abstractroutingdatasource 為我們抽象了一個(gè) dynamicdatasource 解決這一問(wèn)題

spring實(shí)現(xiàn)動(dòng)態(tài)切換、添加數(shù)據(jù)源及源碼分析

簡(jiǎn)單分析下 abstractroutingdatasource 的源碼

spring實(shí)現(xiàn)動(dòng)態(tài)切換、添加數(shù)據(jù)源及源碼分析

spring實(shí)現(xiàn)動(dòng)態(tài)切換、添加數(shù)據(jù)源及源碼分析

targetdatasources 就是我們的多個(gè)數(shù)據(jù)源,在初始化的時(shí)候會(huì)調(diào)用afterpropertiesset(),去解析我們的數(shù)據(jù)源 然后 put 到 resolveddatasources

spring實(shí)現(xiàn)動(dòng)態(tài)切換、添加數(shù)據(jù)源及源碼分析

實(shí)現(xiàn)了 datasource 的 getconnection(); 我們看看 determinetargetdatasource(); 做了什么

spring實(shí)現(xiàn)動(dòng)態(tài)切換、添加數(shù)據(jù)源及源碼分析

通過(guò)下面的 determinecurrentlookupkey();(這個(gè)方法需要我們實(shí)現(xiàn)) 返回一個(gè)key,然后從 resolveddatasources (其實(shí)也就是 targetdatasources) 中 get 一個(gè)數(shù)據(jù)源,實(shí)現(xiàn)了每次調(diào)用 getconnection(); 打開(kāi)連接 切換數(shù)據(jù)源,如果想動(dòng)態(tài)添加的話 只需要重新 set targetdatasources 再調(diào)用 afterpropertiesset() 即可

talk is cheap. show me the code

我使用的springboot版本為 1.5.x,下面是核心代碼

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
/**
 * 多數(shù)據(jù)源配置
 *
 * @author taven
 *
 */
@configuration
@mapperscan("com.gitee.taven.mapper")
public class datasourceconfigurer {
 
 /**
  * datasource 自動(dòng)配置并注冊(cè)
  *
  * @return data source
  */
 @bean("db0")
 @primary
 @configurationproperties(prefix = "datasource.db0")
 public datasource datasource0() {
  return druiddatasourcebuilder.create().build();
 }
 
 /**
  * datasource 自動(dòng)配置并注冊(cè)
  *
  * @return data source
  */
 @bean("db1")
 @configurationproperties(prefix = "datasource.db1")
 public datasource datasource1() {
  return druiddatasourcebuilder.create().build();
 }
 
 /**
  * 注冊(cè)動(dòng)態(tài)數(shù)據(jù)源
  *
  * @return
  */
 @bean("dynamicdatasource")
 public datasource dynamicdatasource() {
  dynamicroutingdatasource dynamicroutingdatasource = new dynamicroutingdatasource();
  map<object, object> datasourcemap = new hashmap<>();
  datasourcemap.put("dynamic_db0", datasource0());
  datasourcemap.put("dynamic_db1", datasource1());
  dynamicroutingdatasource.setdefaulttargetdatasource(datasource0());// 設(shè)置默認(rèn)數(shù)據(jù)源
  dynamicroutingdatasource.settargetdatasources(datasourcemap);
  return dynamicroutingdatasource;
 }
 
 /**
  * sql session factory bean.
  * here to config datasource for sqlsessionfactory
  * <p>
  * you need to add @{@code @configurationproperties(prefix = "mybatis")}, if you are using *.xml file,
  * the {@code 'mybatis.type-aliases-package'} and {@code 'mybatis.mapper-locations'} should be set in
  * {@code 'application.properties'} file, or there will appear invalid bond statement exception
  *
  * @return the sql session factory bean
  */
 @bean
 @configurationproperties(prefix = "mybatis")
 public sqlsessionfactorybean sqlsessionfactorybean() {
  sqlsessionfactorybean sqlsessionfactorybean = new sqlsessionfactorybean();
  // 必須將動(dòng)態(tài)數(shù)據(jù)源添加到 sqlsessionfactorybean
  sqlsessionfactorybean.setdatasource(dynamicdatasource());
  return sqlsessionfactorybean;
 }
 
 /**
  * 事務(wù)管理器
  *
  * @return the platform transaction manager
  */
 @bean
 public platformtransactionmanager transactionmanager() {
  return new datasourcetransactionmanager(dynamicdatasource());
 }
}

通過(guò) threadlocal 獲取線程安全的數(shù)據(jù)源 key

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
package com.gitee.taven.config;
 
public class dynamicdatasourcecontextholder {
 
 private static final threadlocal<string> contextholder = new threadlocal<string>() {
  @override
  protected string initialvalue() {
   return "dynamic_db0";
  }
 };
 
 /**
  * to switch datasource
  *
  * @param key the key
  */
 public static void setdatasourcekey(string key) {
  contextholder.set(key);
 }
 
 /**
  * get current datasource
  *
  * @return data source key
  */
 public static string getdatasourcekey() {
  return contextholder.get();
 }
 
 /**
  * to set datasource as default
  */
 public static void cleardatasourcekey() {
  contextholder.remove();
 }
}

動(dòng)態(tài) 添加、切換數(shù)據(jù)源

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
/**
 * 動(dòng)態(tài)數(shù)據(jù)源
 *
 * @author taven
 *
 */
public class dynamicroutingdatasource extends abstractroutingdatasource {
 
 private final logger logger = loggerfactory.getlogger(getclass());
 
 private static map<object, object> targetdatasources = new hashmap<>();
 
 /**
  * 設(shè)置當(dāng)前數(shù)據(jù)源
  *
  * @return
  */
 @override
 protected object determinecurrentlookupkey() {
  logger.info("current datasource is [{}]", dynamicdatasourcecontextholder.getdatasourcekey());
  return dynamicdatasourcecontextholder.getdatasourcekey();
 }
 
 @override
 public void settargetdatasources(map<object, object> targetdatasources) {
  super.settargetdatasources(targetdatasources);
  dynamicroutingdatasource.targetdatasources = targetdatasources;
 }
 
 /**
  * 是否存在當(dāng)前key的 datasource
  *
  * @param key
  * @return 存在返回 true, 不存在返回 false
  */
 public static boolean isexistdatasource(string key) {
  return targetdatasources.containskey(key);
 }
 
 /**
  * 動(dòng)態(tài)增加數(shù)據(jù)源
  *
  * @param map 數(shù)據(jù)源屬性
  * @return
  */
 public synchronized boolean adddatasource(map<string, string> map) {
  try {
   connection connection = null;
   // 排除連接不上的錯(cuò)誤
   try {
    class.forname(map.get(druiddatasourcefactory.prop_driverclassname));
    connection = drivermanager.getconnection(
      map.get(druiddatasourcefactory.prop_url),
      map.get(druiddatasourcefactory.prop_username),
      map.get(druiddatasourcefactory.prop_password));
    system.out.println(connection.isclosed());
   } catch (exception e) {
    return false;
   } finally {
    if (connection != null && !connection.isclosed())
     connection.close();
   }
   string database = map.get("database");//獲取要添加的數(shù)據(jù)庫(kù)名
   if (stringutils.isblank(database)) return false;
   if (dynamicroutingdatasource.isexistdatasource(database)) return true;
   druiddatasource druiddatasource = (druiddatasource) druiddatasourcefactory.createdatasource(map);
   druiddatasource.init();
   map<object, object> targetmap = dynamicroutingdatasource.targetdatasources;
   targetmap.put(database, druiddatasource);
   // 當(dāng)前 targetdatasources 與 父類 targetdatasources 為同一對(duì)象 所以不需要set
//   this.settargetdatasources(targetmap);
   this.afterpropertiesset();
   logger.info("datasource {} has been added", database);
  } catch (exception e) {
   logger.error(e.getmessage());
   return false;
  }
  return true;
 }
}

可以通過(guò) aop 或者 手動(dòng) dynamicdatasourcecontextholder.setdatasourcekey(string key) 切換數(shù)據(jù)源

需要注意的:當(dāng)我們開(kāi)啟了事務(wù)之后,是無(wú)法在去切換數(shù)據(jù)源的

本文項(xiàng)目源碼:https://gitee.com/yintianwen7/spring-dynamic-datasource

參考文獻(xiàn):https://github.com/helloworlde/springboot-dynamicdatasource

總結(jié)

以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,如果有疑問(wèn)大家可以留言交流,謝謝大家對(duì)服務(wù)器之家的支持。

原文鏈接:https://www.jianshu.com/p/0a485c965b8b

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 在线高清中文字幕 | 欧美综合日韩 | 久久精品毛片 | 亚洲第一成网站 | 国产91免费看 | 久久国产精品99国产 | 欧美亚洲综合网 | 久久视频精品 | 免费黄色大片网站 | 免费午夜视频 | 欧美日韩精品一二三区 | 美女网站黄在线观看 | 一区播放| 91精品国产91久久久久久吃药 | www噜噜偷拍在线视频 | 亚洲一区二区三区四区精品 | 国产激情精品一区二区三区 | 中国洗澡偷拍在线播放 | 午夜生活理论片 | 免费网站看v片在线a | 成人青青草 | 午夜视频在线免费播放 | 最新在线中文字幕 | 一级黄色欧美 | 91九色精品国产 | 伊人av影院 | 激情网站免费观看 | 国产亚洲精久久久久久蜜臀 | 午夜视频在线观 | 99热草| 国产精品久久久久久久久久久久久久久 | 国产精品成人久久 | 一级做a爱片性色毛片 | 久久久久一区二区三区四区五区 | 精品一区二区三区在线视频 | 久久久青青草 | 日本韩国欧美一级片 | 久久久成人精品视频 | 成人福利视频网站 | 欧美亚洲免费 | 国产成人精品午夜视频' |