Spring實現多資料來源動態切換
背景
隨著業務的發展,資料庫壓力的增大,如何分割資料庫的讀寫壓力是我們需要考慮的問題,而能夠動態的切換資料來源就是我們的首要目標。
基礎
Spring作為我們專案的應用容器,也對這方面提供了很好的支援,當我們的持久化框架需要資料庫連線時,我們需要做到動態的切換資料來源,這些Spring的AbstractRoutingDataSource都給我們留了擴充的空間,可以先來看看抽象類AbstractRoutingDataSource在獲取資料庫連線時做了什麼
private Map<Object, DataSource> resolvedDataSources; //從配置檔案讀取到的DataSources的Map
private DataSource resolvedDefaultDataSource; //預設資料來源
public Connection getConnection() throws SQLException {
return determineTargetDataSource().getConnection();
}
public Connection getConnection(String username, String password) throws SQLException {
return determineTargetDataSource().getConnection(username, password);
}
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;
}
protected abstract Object determineCurrentLookupKey();
可以看到AbstractRoutingDataSource在決定目標資料來源的時候,會先呼叫determineCurrentLookupKey()方法得到一個key,我們通過這個key從配置好的resolvedDataSources(Map結構)拿到這次呼叫對應的資料來源,而determineCurrentLookupKey()開放出來讓我們實現
實現
前面提到我們可以通過實現AbstractRoutingDataSource的determineCurrentLookupKey()方法來決定這次呼叫的資料來源。首先說一下思路:當我們的一個執行緒需要針對資料庫做一系列操作時,每次都會去呼叫getConnection()方法獲取資料庫連線,然後執行完後再釋放或歸還資料庫連線(SqlSessionTemplate就是這麼做的),那麼很明顯,我們需要能夠保證每次呼叫Dao層方法時都能動態的切換資料來源,這就需要Spring的AOP:我們定義一個切面,當我們呼叫Dao層方法時,執行我們的邏輯來判斷這次呼叫的資料來源,AOP切面定義如下:
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.PACKAGE, ElementType.TYPE, ElementType.METHOD})
public @interface DataSource {
String value();
}
public Object doAround(ProceedingJoinPoint jp) throws Throwable {
Signature signature = jp.getSignature();
String dataSourceKey = getDataSourceKey(signature);
if (StringUtils.hasText(dataSourceKey)) {
MyDataSource.setDataSourceKey(dataSourceKey);
}
Object jpVal = jp.proceed();
return jpVal;
}
public String getDataSourceKey(Signature signature) {
if (signature == null) return null;
if (signature instanceof MethodSignature) {
MethodSignature methodSignature = (MethodSignature) signature;
Method method = methodSignature.getMethod();
if (method.isAnnotationPresent(DataSource.class)) {
return 方法的註解值;
}
Class declaringClazz = method.getDeclaringClass();
if (declaringClazz.isAnnotationPresent(DataSource.class)) {
return 類級別的註解值;
}
Package pkg = declaringClazz.getPackage();
return 該包路徑的預設資料來源;
}
return null;
}
這裡我們就可以得到我們需要的資料來源,現在就是如何儲存這個值了,因為這個值是我們這個執行緒才需要使用的,所以綜合考慮宣告一個ThreadLocal<String>來儲存不同執行緒的不同值,目前已經解決了當前呼叫方法的資料來源和資料來源值的儲存了,那麼回到前面AbstractRoutingDataSource的determineTargetDataSource()方法中,我們就可以重寫抽象方法determineCurrentLookupKey,返回我們剛剛儲存的資料來源的值,程式碼如下:
public class MyDataSource extends AbstractRoutingDataSource {
private static final ThreadLocal<String> dataSourceKey = new ThreadLocal<String>();
public static void setDataSourceKey(String dataSource) {
dataSourceKey.set(dataSource);
}
protected Object determineCurrentLookupKey() {
String dsName = dataSourceKey.get();
dataSourceKey.remove(); //這裡需要注意的時,每次我們返回當前資料來源的值得時候都需要移除ThreadLocal的值,這是為了避免同一執行緒上一次方法呼叫對之後呼叫的影響
return dsName;
}
}
總結
大體的Spring實現多資料來源的動態切換思路如上
相關文章
- mybatis 多資料來源動態切換MyBatis
- 專案要實現多資料來源動態切換,咋搞?
- Spring-Boot 多資料來源配置+動態資料來源切換+多資料來源事物配置實現主從資料庫儲存分離Springboot資料庫
- spring-data-redis 動態切換資料來源SpringRedis
- AbstractRoutingDataSource 實現動態資料來源切換原理簡單分析
- SpringBoot 這麼實現動態資料來源切換,就很絲滑!Spring Boot
- spring-boot-route(十)多資料來源切換Springboot
- spring框架中多資料來源建立載入並且實現動態切換的配置例項程式碼Spring框架
- 30個類手寫Spring核心原理之動態資料來源切換Spring
- 30個類手寫Spring核心原理之動態資料來源切換(8)Spring
- 基於AOP的動態資料來源切換(附原始碼)原始碼
- 聊聊如何利用apollo與druid整合實現資料來源動態熱切UI
- 多資料來源與動態資料來源的權衡
- siebel切換資料來源【轉】
- Spring Boot整合quartz實現定時任務並支援切換任務資料來源Spring Bootquartz
- Spring 註解動態資料來源設計實踐Spring
- 談談Spring Boot 資料來源載入及其多資料來源簡單實現Spring Boot
- 註解切換雙資料來源
- 使用單例模式來實現動態資料來源管理單例模式
- Spring多資料來源配置Spring
- Springboot通過AOP整合多資料來源,分析@Transaction切換資料來源不生效問題Spring Boot
- SpringBoot2.x 多資料來源切換、druid監控、tkSpring BootUI
- 實現多資料來源事務
- Spring Boot + Mybatis 多資料來源配置實現讀寫分離Spring BootMyBatis
- Spring Boot 配置多資料來源Spring Boot
- Spring Boot 多資料來源配置Spring Boot
- Spring多資料來源獲取Spring
- Sentinel-Go 整合 Nacos 實現外部動態資料來源Go
- nacos實現對minio的動態版本切換
- @Transactional開啟事務導致AbstractRoutingDataSource動態資料來源無法切換的解決方案
- 基於Docker實現MySQL的主從複製和SpringBoot2+MyBatis的動態切換資料來源的讀寫分離DockerMySqlSpring BootMyBatis
- Spring是如何支援多資料來源的Spring
- Spring Boot 入門系列(二十三)整合Mybatis,實現多資料來源配置!Spring BootMyBatis
- 使用ViewPager和TabLayout來實現滑動切換效果ViewpagerTabLayout
- vue 實現tab切換動態載入不同的元件Vue元件
- 使用Spring Boot配置多個資料來源 - UdithSpring Boot
- spring多資料來源下 事務不生效Spring
- BIRT 如何配置動態資料來源
- [MAUI]模仿iOS多工切換卡片滑動的互動實現UIiOS