SpringBoot-多數據源

huangxingA211 8年前發布 | 19K 次閱讀 數據庫 MyBatis JEE框架

來自: http://stackbox.cn/2016-03-spring-boot-multi-datasource/

前言

新項目使用了主從數據庫, 從數據庫用來查詢報表數據, 主數據庫用來CRUD業務數據以及定時插入報表數據, 而且項目中同時使用了 Spring Data JPAMybatis , 配置多個數據源就成了一個很繁瑣的問題。

按照平常的思路, 就是一個數據源配置一個 DataSource , 然后對于Mybatis來講就要配置多個 SqlSessionFactory , DAO和Repository都需要根據文件夾進行區分, 好了, 等你配置完直到能跑的時候就會發現, 項目已經炸了。

一種比較優雅的方法是, 對外只提供一個 DataSource 的虛擬中介, 在配置 SessionFactory / SqlSessionFactory 的時候用的是這個虛擬中介數據源, 等具體要用數據源的時候, 根據某個 Key值來決定到底使用哪一個數據源。 AbstractRoutingDataSource 類就提供了這種功能。

原理

AbstractRoutingDataSource的源碼如下, 這個類實現了 DataSource 接口無誤

public abstract class AbstractRoutingDataSource extends AbstractDataSource implements InitializingBean

 public Connection getConnection() throws SQLException {  
        return determineTargetDataSource().getConnection();  
    } 
    public Connection getConnection(String username, String password) throws SQLException {  
        return determineTargetDataSource().getConnection(username, password);  
    }
}

</div>

然后具體是怎么獲取 Connection的呢? 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;  
}

</div>

好了, 重點來了, 這段代碼的核心其實只有兩點

  • resolvedDefaultDataSource : 一個 Map<Object, DataSource> , 就是在配置的時候手動配置的Key與數據源的對應關系
  • determineCurrentLookupKey() : 用來獲取 Key 值, 需要在子類中實現獲取Key的策略

思路

  1. 項目中配置主從數據源, 并配置自己實現的AbstractRoutingDataSource子類做 主要的(@Primary)的DataSource
  2. 實現AbstractRoutingDataSource子類, Key獲取策略為從一個LocalThread變量中獲取
  3. 設計一個自定義注解,用于在Service層, DAO層, Repository層中使用
  4. 通過AOP的方式去讀取自定義注解, 然后根據注解往LocalThread里塞Key
  5. 因為jetty可能會重用LocalThread, 所以需要在完成之后清空LocalThread變量, 至此, 多數據源配置完成

實現

注意

  1. 要及時清空LocalThread變量, 防止LocalThread重用引起的錯誤
  2. 這種方式, 在配置分布式事務的時候相當復雜, 具體參考 此文

聲明: 本文 “SpringBoot-多數據源” 采用 CC BY-NC-SA 4.0 協議進行授權.

轉載請注明原文地址: http://stackbox.cn/2016-03-spring-boot-multi-datasource/index.html

 本文由用戶 huangxingA211 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!