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

MyBatis實現(xiàn)多數據源動態(tài)切換的核心方法介紹

 更新時間:2026年07月24日 09:33:43   作者:木易?士心  
本文將深入解析MyBatis數據源切換的核心原理與實現(xiàn),涵蓋動態(tài)數據源配置、AOP注解驅動切換、讀寫分離架構等實戰(zhàn)技巧,并重點分析事務邊界問題及解決方案,助您構建高可用數據庫應用

MyBatis 的數據源切換是構建高可用、高性能數據庫應用的關鍵技術。本文將從原理架構、核心代碼實現(xiàn)、用法詳解、初級進階以及優(yōu)勢劣勢等多個維度,結合具體代碼示例,深入剖析這一技術。

一、原理架構

MyBatis 的數據源管理核心在于 DataSource 接口的抽象與路由。在單數據源場景下,配置直接指向一個具體的數據庫連接池。而在多數據源場景下,我們需要引入一個"路由層",根據業(yè)務規(guī)則動態(tài)選擇真正的數據源。

1.1 核心架構組件

下圖展示了多數據源切換的整體架構,包括上下文管理、路由數據源以及實際的數據源工廠:

核心原理說明:

  • Configuration/Environment:MyBatis 的全局配置,傳統(tǒng)方式下這里只能配置一個 Environment。
  • DynamicDataSource:這是實現(xiàn)切換的關鍵。在 Spring 生態(tài)中,我們通常繼承 AbstractRoutingDataSource。它內部維護了一個 Map<Object, Object>,存儲了 Key(如 “master”, “slave”)到真實 DataSource 的映射。
  • DataSourceContextHolder:一個 ThreadLocal 工具類,用于在當前線程中存儲數據源的 Key,確保數據源選擇在同一個線程內是透傳的。

二、核心工作流程與代碼實現(xiàn)

數據源切換并不是發(fā)生在 SQL 解析階段,而是發(fā)生在獲取數據庫連接(Connection)的時刻。

2.1 工作流程時序圖

下圖展示了從 Service 層調用到獲取數據庫連接的完整時序:

2.2 關鍵代碼實現(xiàn)

要實現(xiàn)上述流程,我們需要編寫三個核心部分:上下文管理器、動態(tài)數據源類和配置類。

上下文管理器 (DataSourceContextHolder)

使用 ThreadLocal 保證線程隔離。

public class DataSourceContextHolder {
    private static final ThreadLocal<String> CONTEXT_HOLDER = new ThreadLocal<>();
    /**
     * 設置當前線程的數據源Key
     */
    public static void setDataSourceKey(String key) {
        CONTEXT_HOLDER.set(key);
    }
    /**
     * 獲取當前線程的數據源Key
     */
    public static String getDataSourceKey() {
        return CONTEXT_HOLDER.get();
    }
    /**
     * 清除當前線程的數據源Key(非常重要,防止內存泄漏和污染)
     */
    public static void clearDataSourceKey() {
        CONTEXT_HOLDER.remove();
    }
}

動態(tài)數據源

繼承 Spring 的 AbstractRoutingDataSource,實現(xiàn)路由邏輯。

import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
public class DynamicDataSource extends AbstractRoutingDataSource {
    @Override
    protected Object determineCurrentLookupKey() {
        // 直接從上下文中獲取Key
        return DataSourceContextHolder.getDataSourceKey();
    }
}

三、動態(tài)數據源實現(xiàn)架構與配置

下圖展示了我們在代碼中需要構建的類體系及其依賴關系:

3.1 Spring Boot 配置示例

我們需要配置多個真實的數據源 Bean,并將它們注入到 DynamicDataSource 中。

@Configuration
public class DataSourceConfig {
    // 1. 配置主數據源
    @Bean
    @ConfigurationProperties(prefix = "spring.datasource.master")
    public DataSource masterDataSource() {
        return DataSourceBuilder.create().build();
    }
    // 2. 配置從數據源
    @Bean
    @ConfigurationProperties(prefix = "spring.datasource.slave")
    public DataSource slaveDataSource() {
        return DataSourceBuilder.create().build();
    }
    // 3. 配置動態(tài)數據源(Primary)
    @Bean
    @Primary
    public DynamicDataSource dynamicDataSource(
            @Qualifier("masterDataSource") DataSource masterDataSource,
            @Qualifier("slaveDataSource") DataSource slaveDataSource) {
        
        Map<Object, Object> targetDataSources = new HashMap<>();
        targetDataSources.put("master", masterDataSource);
        targetDataSources.put("slave", slaveDataSource);
        DynamicDataSource dynamicDataSource = new DynamicDataSource();
        // 設置目標數據源映射
        dynamicDataSource.setTargetDataSources(targetDataSources);
        // 設置默認數據源(通常為主庫)
        dynamicDataSource.setDefaultTargetDataSource(masterDataSource);
        
        return dynamicDataSource;
    }
}

四、數據源切換策略與用法

如何決定使用哪個數據源?常見的策略包括注解驅動、方法名約定和手動切換。

下圖梳理了常見的路由策略:

4.1 策略一:自定義注解 + AOP(推薦)

這是最優(yōu)雅的方式,對業(yè)務代碼侵入性最小。

第一步:定義注解

@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface TargetDataSource {
    String value() default "master"; // 默認主庫
}

第二步:定義 AOP 切面

@Aspect
@Component
public class DataSourceAspect {
    // 攔截帶有 @TargetDataSource 注解的方法
    @Before("@annotation(targetDataSource)")
    public void before(JoinPoint point, TargetDataSource targetDataSource) {
        String dataSourceKey = targetDataSource.value();
        if (StringUtils.isNotBlank(dataSourceKey)) {
            DataSourceContextHolder.setDataSourceKey(dataSourceKey);
            System.out.println("切換數據源到: " + dataSourceKey);
        }
    }
    // 執(zhí)行完畢后清除上下文
    @After("@annotation(targetDataSource)")
    public void after(TargetDataSource targetDataSource) {
        DataSourceContextHolder.clearDataSourceKey();
    }
}

第三步:業(yè)務使用

@Service
public class UserService {
    @Autowired
    private UserMapper userMapper;
    // 寫操作走主庫
    @TargetDataSource("master")
    public void addUser(User user) {
        userMapper.insert(user);
    }
    // 讀操作走從庫
    @TargetDataSource("slave")
    public User getUserById(Long id) {
        return userMapper.selectById(id);
    }
}

4.2 策略二:手動編程式切換

在某些復雜的動態(tài)邏輯中(例如根據前端傳入的參數決定租戶庫),可能需要手動切換。

public void processOrder(Long userId, Order order) {
    try {
        // 1. 根據用戶ID計算分片key,切換到對應的用戶庫
        String shardKey = "shard_" + (userId % 4);
        DataSourceContextHolder.setDataSourceKey(shardKey);
        // 2. 執(zhí)行業(yè)務操作(此時會路由到指定分片)
        orderMapper.insert(order);
        
    } finally {
        // 3. 務必在finally中清理,避免影響后續(xù)操作
        DataSourceContextHolder.clearDataSourceKey();
    }
}

五、進階場景:讀寫分離架構

讀寫分離是多數據源最經典的應用場景。應用層通過 AOP 或攔截器,自動將 SELECT 請求發(fā)送至從庫,INSERT/UPDATE/DELETE 發(fā)送至主庫。下圖展示了經典的讀寫分離架構:

實現(xiàn)思路:可以結合 MyBatis 的 Plugin(插件)機制,在 SQL 執(zhí)行前解析 SQL 語句類型。如果以 SELECT 開頭,則調用DataSourceContextHolder.setDataSourceKey("slave"),否則設為 master

六、優(yōu)勢與劣勢分析

任何技術方案都有其適用場景。下圖詳細對比了該技術的優(yōu)勢與劣勢:

6.1 劣勢詳解:事務邊界問題

這是多數據源最大的坑。Spring 的 @Transactional 注解是基于線程綁定的 Connection 來管理的。 如果在一個事務方法中切換了數據源,Spring 的事務管理器可能無法感知,或者導致事務失效。

錯誤示例:

@Transactional // 開啟事務,此時獲取了 Master 的連接
public void updateAndRead() {
    userMapper.updateUser(user); // 使用 Master 連接
    
    // 嘗試切換數據源
    DataSourceContextHolder.setDataSourceKey("slave"); 
    
    // 問題:事務管理器仍持有 Master 的連接,這里可能并不會真的切換,
    // 或者拋出異常,因為 Connection 已經綁定在事務中了。
    userMapper.selectUser(id); 
}

解決方案:

  1. 避免事務內切換:將讀寫操作拆分到不同的事務方法中。
  2. 編程式事務:使用 TransactionTemplate 精確控制事務邊界。
  3. 分布式事務:如果必須跨庫操作(如 Master 寫,Slave 讀并校驗),需要引入 Seata 等分布式事務框架,但這通常用于跨庫寫,讀寫分離場景下通常允許最終一致性。

七、配置實現(xiàn)全流程

下圖描述了從零開始搭建動態(tài)數據源的完整配置步驟:

八、進階應用場景與演進

隨著業(yè)務復雜度的提升,數據源切換技術也衍生出了多種高級應用場景。

下圖展示了多數據源技術在不同階段的應用場景及演進:

技術演進時間線:

九、總結

MyBatis 的數據源切換機制通過 AbstractRoutingDataSourceThreadLocal 的巧妙結合,為我們提供了一種輕量級、靈活的數據路由方案。核心要點回顧:

  1. ThreadLocal 是靈魂:它保證了在多線程環(huán)境下,每個請求的數據源選擇互不干擾。
  2. AOP 是翅膀:通過切面將數據源選擇邏輯從業(yè)務代碼中剝離,保持代碼整潔。
  3. 事務是雙刃劍:在使用多數據源時,務必清醒地認識事務邊界的限制,避免事務失效。

在實際項目中,建議從簡單的讀寫分離開始,逐步根據業(yè)務需求引入更復雜的路由策略,并做好充分的監(jiān)控與容錯準備。

以上就是MyBatis實現(xiàn)多數據源動態(tài)切換的核心方法介紹的詳細內容,更多關于MyBatis數據源切換的資料請關注腳本之家其它相關文章!

相關文章

  • Spring Batch批量處理數據實現(xiàn)方式

    Spring Batch批量處理數據實現(xiàn)方式

    SpringBatch是一個用于創(chuàng)建高效、健壯批量數據處理應用的框架,支持事務管理、并發(fā)處理、重試機制、跳過機制等特性,它由Spring框架的一部分,包括Job、Step、ItemReader、ItemProcessor、ItemWriter等核心組件,在SpringBoot項目中集成SpringBatch
    2025-12-12
  • Spring Boot整合Mybatis并完成CRUD操作的實現(xiàn)示例

    Spring Boot整合Mybatis并完成CRUD操作的實現(xiàn)示例

    這篇文章主要介紹了Spring Boot整合Mybatis并完成CRUD操作的實現(xiàn)示例,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-12-12
  • Spring @Cacheable自定義緩存過期時間的實現(xiàn)示例

    Spring @Cacheable自定義緩存過期時間的實現(xiàn)示例

    本文主要介紹了Spring @Cacheable自定義緩存過期時間的實現(xiàn)示例,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2024-05-05
  • elasticsearch聚合查詢實踐示例

    elasticsearch聚合查詢實踐示例

    這篇文章主要為大家介紹了elasticsearch聚合查詢實踐示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-12-12
  • SpringQuartz集群支持JDBC存儲與分布式執(zhí)行的最佳實踐

    SpringQuartz集群支持JDBC存儲與分布式執(zhí)行的最佳實踐

    SpringQuartz集群通過JDBC存儲和分布式執(zhí)行機制,有效解決了單點故障和擴展性問題,本文將詳細介紹SpringQuartz集群支持的實現(xiàn)原理、配置方法和最佳實踐,助力開發(fā)者構建穩(wěn)定可靠的分布式調度系統(tǒng),感興趣的朋友一起看看吧
    2025-04-04
  • SpringBoot圖文并茂詳解如何引入mybatis與連接Mysql數據庫

    SpringBoot圖文并茂詳解如何引入mybatis與連接Mysql數據庫

    這篇文章主要介紹了SpringBoot如何引入mybatis與連接Mysql數據庫,本文通過圖文并茂的形式給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-07-07
  • Java入門異常處理最佳實踐

    Java入門異常處理最佳實踐

    本文詳細介紹了Java異常處理的核心概念、體系結構、處理方式、執(zhí)行流程,并提供了實現(xiàn)自定義異常的方法和開發(fā)中的最佳實踐,感興趣的朋友跟隨小編一起看看吧
    2026-03-03
  • Java使用BigDecimal解決精度丟失問題

    Java使用BigDecimal解決精度丟失問題

    本文詳細解釋了浮點型數據因二進制和十進制不兼容而導致的精度丟失問題,并指出BigDecimal是解決該問題的有效方法,文中的示例代碼講解詳細,感興趣的小伙伴可以了解下
    2026-04-04
  • Java 通過 二三法 巧解前端數據顯示

    Java 通過 二三法 巧解前端數據顯示

    實踐來源于理論,做開發(fā)前肯定要先了解相關的規(guī)則和原理,看到標題或許你會好奇什么是二三法。本篇文章帶你深入了解,需要的朋友可以參考下
    2021-10-10
  • Java-性能分析和監(jiān)控工具深入詳解

    Java-性能分析和監(jiān)控工具深入詳解

    這篇文章主要介紹了Java-性能分析和監(jiān)控工具深入詳解,文章內容詳細,簡單易懂,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2023-01-01

最新評論

无极县| 鹿邑县| 同德县| 宜宾县| 米泉市| 察隅县| 大厂| 酉阳| 岳西县| 玉屏| 昌平区| 军事| 洞口县| 嵩明县| 石门县| 涟源市| 乌鲁木齐县| 镇赉县| 延安市| 孟州市| 正蓝旗| 自治县| 潼关县| 宣汉县| 灌云县| 喜德县| 闵行区| 新源县| 淮北市| 澎湖县| 肇庆市| 镇平县| 陇西县| 海安县| 水城县| 顺平县| 大方县| 杭锦后旗| 宜春市| 若尔盖县| 浮梁县|