最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

???????Spring多租戶數(shù)據(jù)源管理 AbstractRoutingDataSource

 更新時(shí)間:2022年05月16日 10:28:33   作者:? 小姐姐味道?  ?  
本文技術(shù)了???????Spring多租戶數(shù)據(jù)源管理 AbstractRoutingDataSource,下文詳細(xì)內(nèi)容介紹,需要的小伙伴可以參考一下

前言:

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

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

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

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

1.基本原理

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

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

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

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

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

在Java中,可以使用ThreadLocal綁定這個(gè)透?jìng)鞯膶傩?。像Spring的嵌套事務(wù)等實(shí)現(xiàn)的原理,也是基于ThreadLocal去運(yùn)行的。所以,DataSourceContextHolder.本質(zhì)上是一個(gè)操作ThreadLocal的類。

public?class?DataSourceContextHolder?{
????private?static?InheritableThreadLocal<String>?dbKey?=?new?InheritableThreadLocal<>();

????public?static?void?setDbKey(String?key){
????????dbKey.set(key);
????}

????public?static?String?getDbKey(){
????????return?dbKey.get();
????}
}

2.配置代碼

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

multi:
??dbs:
????db-a:
??????driver-class-name:?org.h2.Driver
??????url:?jdbc:h2:mem:dba;MODE=MYSQL;DATABASE_TO_UPPER=false;
????db-b:
??????driver-class-name:?org.h2.Driver
??????url:?jdbc:h2:mem:dbb;MODE=MYSQL;DATABASE_TO_UPPER=false;

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

@ConfigurationProperties(prefix?=?"multi")
@Configuration
public?class?DbsProperties?{
????private?Map<String,?Map<String,?String>>?dbs?=?new?HashMap<>();

????public?Map<String,?Map<String,?String>>?getDbs()?{
????????return?dbs;
????}

????public?void?setDbs(Map<String,?Map<String,?String>>?dbs)?{
????????this.dbs?=?dbs;
????}
}

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

public?class?DynamicDataSource?extends?AbstractRoutingDataSource?{
????@Override
????protected?Object?determineCurrentLookupKey()?{
????????return?DataSourceContextHolder.getDbKey();
????}
}

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

@Configuration
public?class?DynamicDataSourceConfiguration?{
????@Autowired
????DbsProperties?properties;
????@Bean
????public?DataSource?dataSource(){
????????DynamicDataSource?dataSource?=?new?DynamicDataSource();
????????final?Map<Object,Object>?targetDataSource??=?getTargetDataSource();
????????dataSource.setTargetDataSources(targetDataSource);
????????//TODO?默認(rèn)數(shù)據(jù)庫需要設(shè)置
????????dataSource.setDefaultTargetDataSource(targetDataSource.values().iterator().next());
????????return?dataSource;
????}

????private?Map<Object,Object>?getTargetDataSource(){
????????Map<Object,Object>?dataSources?=?new?HashMap<>();
????????this.properties.getDbs().entrySet().stream()
????????????????.forEach(e->{
????????????????????DriverManagerDataSource?dmd?=?new?DriverManagerDataSource();
????????????????????dmd.setUrl(e.getValue().get("url"));
????????????????????dmd.setDriverClassName(e.getValue().get("driver-class-name"));
????????????????????dataSources.put(e.getKey(),dmd);
????????????????});
????????return??dataSources;
????}
}

3.問題

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

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

總結(jié)

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

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

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

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

到此這篇關(guān)于Spring多租戶數(shù)據(jù)源管理 AbstractRoutingDataSource的文章就介紹到這了,更多相關(guān)AbstractRoutingDataSource內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java中絕對(duì)值函數(shù)的介紹與其妙用

    Java中絕對(duì)值函數(shù)的介紹與其妙用

    這篇文章主要給大家介紹了Java中絕對(duì)值函數(shù)的介紹與其妙用,其中包括絕對(duì)值函數(shù)用來獲取表達(dá)式的絕對(duì)值和絕對(duì)值函數(shù)實(shí)現(xiàn)降序+升序輸出。文章末尾給出了實(shí)例介紹,有需要的朋友們可以參考學(xué)習(xí),下面來一起看看吧。
    2017-01-01
  • Spring MVC 使用支付寶接口完成在線支付的示例代碼

    Spring MVC 使用支付寶接口完成在線支付的示例代碼

    本篇文章主要介紹了Spring MVC 使用支付寶接口完成在線支付的示例代碼,具有一定的參考價(jià)值,有興趣的可以了解一下
    2017-08-08
  • Java編程接口回調(diào)一般用法代碼解析

    Java編程接口回調(diào)一般用法代碼解析

    本文的主要內(nèi)容是同過實(shí)際代碼向大家展示Java編程中接口回調(diào)的一般用法,具有一定參考價(jià)值,需要的朋友可以了解下
    2017-09-09
  • 基于springcloud異步線程池、高并發(fā)請(qǐng)求feign的解決方案

    基于springcloud異步線程池、高并發(fā)請(qǐng)求feign的解決方案

    這篇文章主要介紹了基于springcloud異步線程池、高并發(fā)請(qǐng)求feign的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2021-02-02
  • SpringBoot通過@Value實(shí)現(xiàn)給靜態(tài)變量注入值詳解

    SpringBoot通過@Value實(shí)現(xiàn)給靜態(tài)變量注入值詳解

    這篇文章主要介紹了springboot如何通過@Value給靜態(tài)變量注入值,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-07-07
  • SpringBoot通過請(qǐng)求對(duì)象獲取輸入流無數(shù)據(jù)

    SpringBoot通過請(qǐng)求對(duì)象獲取輸入流無數(shù)據(jù)

    這篇文章主要介紹了使用SpringBoot通過請(qǐng)求對(duì)象獲取輸入流無數(shù)據(jù),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-03-03
  • Java實(shí)現(xiàn)的自定義類加載器示例

    Java實(shí)現(xiàn)的自定義類加載器示例

    這篇文章主要介紹了Java實(shí)現(xiàn)的自定義類加載器,結(jié)合具體實(shí)例形式分析了java自定義類加載器的原理與具體實(shí)現(xiàn)技巧,需要的朋友可以參考下
    2019-07-07
  • Java線程并發(fā)工具類CountDownLatch原理及用法

    Java線程并發(fā)工具類CountDownLatch原理及用法

    這篇文章主要介紹了Java線程并發(fā)工具類CountDownLatch原理及用法,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-10-10
  • nacos配置在代碼中引用的方法講解

    nacos配置在代碼中引用的方法講解

    這篇文章主要介紹了nacos配置在代碼中如何引用,如果主配置中配置的內(nèi)容和拓展配置的內(nèi)容重復(fù)則按主配置的配置 ,如果拓展配置中的內(nèi)容和另一個(gè)拓展配置中的內(nèi)容重復(fù),則按下標(biāo)大的配置作為最終的配置,對(duì)nacos配置代碼引用相關(guān)知識(shí)感興趣朋友一起看看吧
    2022-12-12
  • java基于JSON實(shí)現(xiàn)前后端交互(附代碼)

    java基于JSON實(shí)現(xiàn)前后端交互(附代碼)

    本文主要介紹了java基于JSON實(shí)現(xiàn)前后端交互,通過實(shí)際代碼示例展示了如何前后端JSON交互,具有一定的參考價(jià)值,感興趣的可以了解一下
    2024-01-01

最新評(píng)論

长顺县| 黑水县| 明水县| 南安市| 辉南县| 朔州市| SHOW| 普安县| 辽阳市| 松溪县| 皋兰县| 溧阳市| 革吉县| 昭平县| 凌海市| 辽源市| 育儿| 富顺县| 东丰县| 石台县| 四平市| 泾阳县| 阿巴嘎旗| 郸城县| 东方市| 东乌| 洛浦县| 北流市| 西和县| 定边县| 上高县| 东台市| 腾冲县| 塔河县| 响水县| 大城县| 伊川县| 南靖县| 黄冈市| 襄汾县| 松原市|