日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

多租户多数据源实现

發布時間:2024/10/5 编程问答 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 多租户多数据源实现 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

最近遇到了做多數據源多需求,我們多系統是基于多租戶多,要求是不同多租戶能訪問不同多數據源,而達到提高性能和良好的容災能力。

我們是基于druid+mysql+springboot的:

那我了解到Spring boot提供了AbstractRoutingDataSource的抽象類根據用戶定義的規則選擇當前的數據源,這樣我們可以在執行查詢之前,設置使用的數據源。實現可動態路由的數據源,在每次數據庫查詢操作前執行。它的抽象方法determineCurrentLookupKey() 決定使用哪個數據源。

AbstractRoutingDataSource

org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource 源碼的介紹:

/**
Abstract {@link javax.sql.DataSource} implementation that routes {@link #getConnection()}
?* calls to one of various target DataSources based on a lookup key. The latter is usually
?* (but not necessarily) determined through some thread-bound transaction context.
?*
?* @author Juergen Hoeller
?* @since 2.0.1
?* @see #setTargetDataSources
?* @see #setDefaultTargetDataSource
?* @see #determineCurrentLookupKey()
?*/
?

AbstractRoutingDataSource就是DataSource的抽象,基于lookup key的方式在多個數據庫中進行切換。重點關注setTargetDataSources,setDefaultTargetDataSource,determineCurrentLookupKey三個方法。那么AbstractRoutingDataSource就是Spring多數據源的關鍵了。

  • setTargetDataSources設置備選的數據源集合
  • ?setDefaultTargetDataSource設置默認數據源
  • determineCurrentLookupKey決定當前數據源的對應的key
  • 但是好像3個方法都沒有包含切換數據庫的邏輯啊!仔細閱讀源碼發現一個方法,determineTargetDataSource方法,其實它才是獲取數據源的實現。源碼如下:

    ? ? //切換數據庫的核心邏輯
    ? ? protected DataSource determineTargetDataSource() {
    ?? ??? ?Assert.notNull(this.resolvedDataSources, "DataSource router not initialized");
    ?? ??? ?Object lookupKey = determineCurrentLookupKey();
    ?? ??? ?DataSource dataSource = this.resolvedDataSources.get(lookupKey);
    ?? ??? ?if (dataSource == null && (this.lenientFallback || lookupKey == null)) {
    ?? ??? ??? ?dataSource = this.resolvedDefaultDataSource;
    ?? ??? ?}
    ?? ??? ?if (dataSource == null) {
    ?? ??? ??? ?throw new IllegalStateException
    ? ? ? ? ? ? ? ("Cannot determine target DataSource for lookup key [" + lookupKey + "]");
    ?? ??? ?}
    ?? ??? ?return dataSource;
    ?? ?}
    ? ? //之前的2個核心方法
    ?? ?public void setTargetDataSources(Map<Object, Object> targetDataSources) {
    ?? ??? ?this.targetDataSources = targetDataSources;
    ?? ?}
    ? ? public void setDefaultTargetDataSource(Object defaultTargetDataSource) {
    ?? ??? ?this.defaultTargetDataSource = defaultTargetDataSource;
    ?? ?}

    簡單說就是,根據determineCurrentLookupKey獲取的key,在resolvedDataSources這個Map中查找對應的datasource!,注意determineTargetDataSource方法竟然不使用的targetDataSources!

    那一定存在resolvedDataSources與targetDataSources的對應關系。接著翻閱代碼,發現一個afterPropertiesSet方法(Spring源碼中InitializingBean接口中的方法),這個方法將targetDataSources的值賦予了resolvedDataSources。源碼如下
    ?

    ?? ?@Override
    ?? ?public void afterPropertiesSet() {
    ?? ??? ?if (this.targetDataSources == null) {
    ?? ??? ??? ?throw new IllegalArgumentException("Property 'targetDataSources' is required");
    ?? ??? ?}
    ?? ??? ?this.resolvedDataSources = new HashMap<Object, DataSource>(this.targetDataSources.size());
    ?? ??? ?for (Map.Entry<Object, Object> entry : this.targetDataSources.entrySet()) {
    ?? ??? ??? ?Object lookupKey = resolveSpecifiedLookupKey(entry.getKey());
    ?? ??? ??? ?DataSource dataSource = resolveSpecifiedDataSource(entry.getValue());
    ?? ??? ??? ?this.resolvedDataSources.put(lookupKey, dataSource);
    ?? ??? ?}
    ?? ??? ?if (this.defaultTargetDataSource != null) {
    ?? ??? ??? ?this.resolvedDefaultDataSource = resolveSpecifiedDataSource(this.defaultTargetDataSource);
    ?? ??? ?}
    ?? ?}

    afterPropertiesSet?方法,熟悉Spring的都知道,它在bean實例已經創建好,且屬性值和依賴的其他bean實例都已經注入以后執行。

    也就是說調用,targetDataSources,defaultTargetDataSource的賦值一定要在afterPropertiesSet前邊執行。

    AbstractRoutingDataSource簡單總結:

    AbstractRoutingDataSource,內部有一個Map<Object,DataSource>的域resolvedDataSources
    determineTargetDataSource方法通過determineCurrentLookupKey方法獲得key,進而從map中取得對應的DataSource。
    setTargetDataSources 設置 targetDataSources
    setDefaultTargetDataSource 設置 defaultTargetDataSource,
    targetDataSources和defaultTargetDataSource 在afterPropertiesSet分別轉換為resolvedDataSources和resolvedDefaultDataSource。
    targetDataSources,defaultTargetDataSource的賦值一定要在afterPropertiesSet前邊執行。

    簡單寫下為代碼邏輯:

    1、先寫一個類繼承AbstractRoutingDataSource,實現determineCurrentLookupKey方法,和afterPropertiesSet方法。afterPropertiesSet方法中調用setDefaultTargetDataSource和setTargetDataSources方法之后調用super.afterPropertiesSet。

    2、定義一個切面在事務切面之前執行,確定真實數據源對應的key

    3、用ThreadLocal傳遞真實數據源對應的key

    4、定義一個druidDataSourceCreator類,每次創建數據源都從這里取

    參考文章:1、https://blog.csdn.net/qq_36903131/article/details/89372011

    ? ? ? ? ? ? ? ? ? 2、如果自己不想實現可以使用mybatis-plus的實現https://github.com/baomidou/dynamic-datasource-spring-boot-starter

    ? ? ? ? ? ? ? ? ? ? ? ? 更建議是自己參考其設計模式進行設計

    ? ? ? ? ? ? ? ? ?3、https://blog.csdn.net/floor2011/article/details/100907108

    ?

    ?

    ?

    總結

    以上是生活随笔為你收集整理的多租户多数据源实现的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。