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

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

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術(shù)|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務(wù)器之家 - 編程語言 - Java教程 - 實用:Spring的多租戶數(shù)據(jù)源管理 AbstractRoutingDataSource!

實用:Spring的多租戶數(shù)據(jù)源管理 AbstractRoutingDataSource!

2022-01-12 23:01小姐姐味道小姐姐養(yǎng)的狗02號 Java教程

除了引入一些分庫分表組件,Spring自身提供了AbstractRoutingDataSource的方式,讓多數(shù)數(shù)據(jù)源的管理成為可能。其實分庫分表組件使用上限制很多,你不得不首先梳理這座屎山,接下來還要忍受中間件對你的SQL的苛刻要求;反而是一些野路

實用:Spring的多租戶數(shù)據(jù)源管理 AbstractRoutingDataSource!

很多情況,我們確實需要在一個服務(wù)中訪問多個數(shù)據(jù)源。雖然它讓整體設(shè)計變的不那么優(yōu)雅,但真實的世界確實需要它。比如,你的業(yè)務(wù)為兩個比較大的客戶服務(wù),但你希望他們能夠共用一套代碼。

也就是說,你的代碼剛開始沒有考慮設(shè)計多租戶這種功能,但后面又有這種蛋疼的需求。但還好不是爆炸式的租戶增長。

除了引入一些分庫分表組件,Spring自身提供了AbstractRoutingDataSource的方式,讓多數(shù)數(shù)據(jù)源的管理成為可能。其實分庫分表組件使用上限制很多,你不得不首先梳理這座屎山,接下來還要忍受中間件對你的SQL的苛刻要求;反而是一些野路子,能夠讓代碼的改動量盡量的減少。

心動不如行動。接下來,就讓我們來看一下它的具體實現(xiàn)吧。

1.基本原理

多數(shù)據(jù)源能進行動態(tài)切換的核心就是spring底層提供了AbstractRoutingDataSource類進行數(shù)據(jù)源路由。AbstractRoutingDataSource實現(xiàn)了DataSource接口,所以我們可以將其直接注入到DataSource的屬性上。

我們主要繼承這個類,實現(xiàn)里面的方法determineCurrentLookupKey(),而此方法只需要返回一個數(shù)據(jù)庫的名稱即可。

比如,Controller通過拿到前端業(yè)務(wù)傳遞的數(shù)值,進行業(yè)務(wù)邏輯分發(fā)。它就可以手動設(shè)置當(dāng)前請求的數(shù)據(jù)庫標(biāo)識,然后路由到正確的庫表里面。

  1. @Controller 
  2. public class ARDTestController { 
  3.     @GetMapping("test"
  4.     public void chifeng(){ 
  5.         //db-a 應(yīng)該是上層傳遞下來的屬性,我們可以把它放在ThreadLocal里 
  6.         DataSourceContextHolder.setDbKey("db-a"); 
  7.     } 

那么當(dāng)sql語句執(zhí)行的時候,它如何知道自己需要切換到哪個數(shù)據(jù)源呢?是不是需要把db-a這個屬性一直透傳下去呢?

在Java中,可以使用ThreadLocal綁定這個透傳的屬性。像Spring的嵌套事務(wù)等實現(xiàn)的原理,也是基于ThreadLocal去運行的。所以,DataSourceContextHolder.本質(zhì)上是一個操作ThreadLocal的類。

  1. public class DataSourceContextHolder { 
  2.     private static InheritableThreadLocal<String> dbKey = new InheritableThreadLocal<>(); 
  3.  
  4.     public static void setDbKey(String key){ 
  5.         dbKey.set(key); 
  6.     } 
  7.  
  8.     public static String getDbKey(){ 
  9.         return dbKey.get(); 
  10.     } 

2.配置代碼

首先,我們自定義了配置文件的格式。如下面的代碼,就配置了db-a和db-b兩個數(shù)據(jù)庫。

  1. multi: 
  2.   dbs: 
  3.     db-a: 
  4.       driver-class-name: org.h2.Driver 
  5.       url: jdbc:h2:mem:dba;MODE=MYSQL;DATABASE_TO_UPPER=false
  6.     db-b: 
  7.       driver-class-name: org.h2.Driver 
  8.       url: jdbc:h2:mem:dbb;MODE=MYSQL;DATABASE_TO_UPPER=false

然后,我們將它解析稱properties。

  1. @ConfigurationProperties(prefix = "multi"
  2. @Configuration 
  3. public class DbsProperties { 
  4.     private Map<String, Map<String, String>> dbs = new HashMap<>(); 
  5.  
  6.     public Map<String, Map<String, String>> getDbs() { 
  7.         return dbs; 
  8.     } 
  9.  
  10.     public void setDbs(Map<String, Map<String, String>> dbs) { 
  11.         this.dbs = dbs; 
  12.     } 

接下來一步,需要配置整個應(yīng)用所默認(rèn)的數(shù)據(jù)源。如你所見,它的主要邏輯,就是在運行的時候,從ThreadLocal里取出提前設(shè)置的這個值。

  1. public class DynamicDataSource extends AbstractRoutingDataSource { 
  2.     @Override 
  3.     protected Object determineCurrentLookupKey() { 
  4.         return DataSourceContextHolder.getDbKey(); 
  5.     } 

最后一步,設(shè)置整個項目中默認(rèn)的DataSource。注意,我們生成DynamicDataSource之后,還需要提供targetDataSource和defaultTargetDataSource兩個屬性的值,才能夠正常運行。

  1. @Configuration 
  2. public class DynamicDataSourceConfiguration { 
  3.     @Autowired 
  4.     DbsProperties properties; 
  5.  
  6.     @Bean 
  7.     public DataSource dataSource(){ 
  8.         DynamicDataSource dataSource = new DynamicDataSource(); 
  9.         final Map<Object,Object> targetDataSource  = getTargetDataSource(); 
  10.         dataSource.setTargetDataSources(targetDataSource); 
  11.         //TODO 默認(rèn)數(shù)據(jù)庫需要設(shè)置 
  12.         dataSource.setDefaultTargetDataSource(targetDataSource.values().iterator().next()); 
  13.         return dataSource; 
  14.     } 
  15.  
  16.     private Map<Object,Object> getTargetDataSource(){ 
  17.         Map<Object,Object> dataSources = new HashMap<>(); 
  18.         this.properties.getDbs().entrySet().stream() 
  19.                 .forEach(e->{ 
  20.                     DriverManagerDataSource dmd = new DriverManagerDataSource(); 
  21.                     dmd.setUrl(e.getValue().get("url")); 
  22.                     dmd.setDriverClassName(e.getValue().get("driver-class-name")); 
  23.                     dataSources.put(e.getKey(),dmd); 
  24.                 }); 
  25.         return  dataSources; 
  26.     } 

3.問題

通過以上簡單的代碼,就可以實現(xiàn)Spring簡單的多數(shù)據(jù)源管理。但明顯的,它還存在很多問題。

  • 需要產(chǎn)品設(shè)計選擇模式,進行業(yè)務(wù)切換。
  • 前端可以采用放在localStroage的方式,保存屬性,可使用攔截器方式將變量每次都傳遞。
  • 后端每次請求,都需要帶上目標(biāo)db,可以采用放在ThreadLocal里的方式。但ThreadLocal有線程透傳的問題,如果任務(wù)里開啟了子線程,則變量不能共享。
  • 由于表是動態(tài)選擇的,所以JPA自動創(chuàng)建和update等模式,將不可用。不方便測試和單元測試,在測試接口的時候,也需要每次強制指定指向的庫。
  • 由于是修改數(shù)據(jù)源的模式,每次增加庫,都需要重新啟動上線才可以。如果要做到動態(tài)性,數(shù)據(jù)源銷毀是個問題。

End

對于一個微服務(wù)來說,有很多默認(rèn)的限制策略,比如,不同域之間的服務(wù)是不能共享一個數(shù)據(jù)庫的。這些基本原則,把微服務(wù)整的清清爽爽,是一些基本的原則。

同理的,如果我們在設(shè)計開始,就給每一張表加上租戶的字段ID,那么寫代碼的時候就順暢的多。但是世界上沒有這么多如果。

原則為何而存在?當(dāng)然是為了讓人去打破的。

編程只是工具,反正代碼在自己手里,怎么玩,看需要,也看心情。條條大路通羅馬,曲徑通幽處,風(fēng)光無限好。

作者簡介:小姐姐味道 (xjjdog),一個不允許程序員走彎路的公眾號。聚焦基礎(chǔ)架構(gòu)和Linux。十年架構(gòu),日百億流量,與你探討高并發(fā)世界,給你不一樣的味道。

原文鏈接:https://mp.weixin.qq.com/s/KS8GJEqFIRTiSiWsmRTKNg

延伸 · 閱讀

精彩推薦
  • Java教程Java使用SAX解析xml的示例

    Java使用SAX解析xml的示例

    這篇文章主要介紹了Java使用SAX解析xml的示例,幫助大家更好的理解和學(xué)習(xí)使用Java,感興趣的朋友可以了解下...

    大行者10067412021-08-30
  • Java教程xml與Java對象的轉(zhuǎn)換詳解

    xml與Java對象的轉(zhuǎn)換詳解

    這篇文章主要介紹了xml與Java對象的轉(zhuǎn)換詳解的相關(guān)資料,需要的朋友可以參考下...

    Java教程網(wǎng)2942020-09-17
  • Java教程20個非常實用的Java程序代碼片段

    20個非常實用的Java程序代碼片段

    這篇文章主要為大家分享了20個非常實用的Java程序片段,對java開發(fā)項目有所幫助,感興趣的小伙伴們可以參考一下 ...

    lijiao5352020-04-06
  • Java教程Java BufferWriter寫文件寫不進去或缺失數(shù)據(jù)的解決

    Java BufferWriter寫文件寫不進去或缺失數(shù)據(jù)的解決

    這篇文章主要介紹了Java BufferWriter寫文件寫不進去或缺失數(shù)據(jù)的解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望...

    spcoder14552021-10-18
  • Java教程小米推送Java代碼

    小米推送Java代碼

    今天小編就為大家分享一篇關(guān)于小米推送Java代碼,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧...

    富貴穩(wěn)中求8032021-07-12
  • Java教程升級IDEA后Lombok不能使用的解決方法

    升級IDEA后Lombok不能使用的解決方法

    最近看到提示IDEA提示升級,尋思已經(jīng)有好久沒有升過級了。升級完畢重啟之后,突然發(fā)現(xiàn)好多錯誤,本文就來介紹一下如何解決,感興趣的可以了解一下...

    程序猿DD9332021-10-08
  • Java教程Java8中Stream使用的一個注意事項

    Java8中Stream使用的一個注意事項

    最近在工作中發(fā)現(xiàn)了對于集合操作轉(zhuǎn)換的神器,java8新特性 stream,但在使用中遇到了一個非常重要的注意點,所以這篇文章主要給大家介紹了關(guān)于Java8中S...

    阿杜7482021-02-04
  • Java教程Java實現(xiàn)搶紅包功能

    Java實現(xiàn)搶紅包功能

    這篇文章主要為大家詳細(xì)介紹了Java實現(xiàn)搶紅包功能,采用多線程模擬多人同時搶紅包,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙...

    littleschemer13532021-05-16
主站蜘蛛池模板: 中国av一级片 | 国产三级午夜理伦三级 | 一级毛片在线观看免费 | 99精品国产一区二区三区 | 一区二区三区日韩在线 | 日本久久精品视频 | 亚洲精品无码不卡在线播放he | 欧美成人鲁丝片在线观看 | 成人性生活视频在线观看 | 九九热久久免费视频 | xxxeexxx性国产 | 日韩在线黄色片 | 亚洲国产精品久久久久久久久 | h色网站免费观看 | 欧美色大成网站www永久男同 | 人人玩人人爽 | 国产一区二区视频精品 | 久久综合福利 | chinese xvideos gay | 主人在调教室性调教女仆游戏 | 久久综合艹 | 国产一级不卡毛片 | 国色天香综合网 | 香蕉国产9| 亚洲免费观看视频 | 在线a毛片免费视频观看 | 国产精品99久久久久久宅女 | 日本aaaa片毛片免费观看视频 | 91,视频免费看| 干色视频| 视频一区二区中文字幕 | 黄网站在线免费 | 日韩精品中文字幕在线播放 | 色人阁导航 | 日韩一级免费毛片 | 国产午夜精品久久久久久久蜜臀 | 成人一级视频在线观看 | 免费观看欧美一级片 | 毛片在线免费视频 | 亚洲国产精品久久久久久久久久久 | 精品一区二区三区毛片 |