SpringBoot-多數據源
來自: http://stackbox.cn/2016-03-spring-boot-multi-datasource/
前言
新項目使用了主從數據庫, 從數據庫用來查詢報表數據, 主數據庫用來CRUD業務數據以及定時插入報表數據, 而且項目中同時使用了 Spring Data JPA 和 Mybatis , 配置多個數據源就成了一個很繁瑣的問題。
按照平常的思路, 就是一個數據源配置一個 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的策略
思路
- 項目中配置主從數據源, 并配置自己實現的AbstractRoutingDataSource子類做 主要的(@Primary)的DataSource
- 實現AbstractRoutingDataSource子類, Key獲取策略為從一個LocalThread變量中獲取
- 設計一個自定義注解,用于在Service層, DAO層, Repository層中使用
- 通過AOP的方式去讀取自定義注解, 然后根據注解往LocalThread里塞Key
- 因為jetty可能會重用LocalThread, 所以需要在完成之后清空LocalThread變量, 至此, 多數據源配置完成
實現
注意
- 要及時清空LocalThread變量, 防止LocalThread重用引起的錯誤
- 這種方式, 在配置分布式事務的時候相當復雜, 具體參考 此文
聲明: 本文 “SpringBoot-多數據源” 采用 CC BY-NC-SA 4.0 協議進行授權.
轉載請注明原文地址: http://stackbox.cn/2016-03-spring-boot-multi-datasource/index.html