首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 綜合教學

Spring + MyBatis 多數據源架構:從簡單隔離到 AOP 動態路由實戰 Spring + MyBatis 多數據源架構:從簡單隔離到 AOP 動態路由實戰

     編輯:Java 綜合教學

多數據源兩大業務場景

  1. 完全獨立:不同業務庫無關聯(如平台庫 + 遊戲庫),可視為獨立項目開發。
  2. 主從複制:Master 寫、Slave 讀;需按業務靈活路由(耗時查詢走 Slave、實時查詢走 Master)。

方案一:Spring XML 直接配置多套獨立組件(適合場景 1)

為每個數據源定義完整 Bean 鏈:

<bean name="dataSource" class="DruidDataSource">...</bean>
<bean id="sqlSessionFactory" class="SqlSessionFactoryBean">
    <property name="dataSource" ref="dataSource"/> ...
</bean>
<bean id="transactionManager" class="DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource"/>
</bean>
<tx:annotation-driven transaction-manager="transactionManager"/>
<bean class="MapperScannerConfigurer">
    <property name="basePackage" value="net.aazj.mapper"/>
    <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/> <!-- 關鍵綁定 -->
</bean>

<!-- 第二套:dataSource_2, sqlSessionFactory_2, transactionManager_2, mapper2 -->
  • 優點:配置直觀、隔離徹底。
  • 缺點:不支持分布式事務(單事務跨庫)、擴展靈活性差(主從場景需精細路由)。

方案二:AbstractRoutingDataSource + AOP 動態路由(適合場景 2,推薦)

核心組件

  1. 枚舉標識:enum DataSources { MASTER, SLAVE }
  2. ThreadLocal 持有當前線程數據源標識:
    public class DataSourceTypeManager {
        private static final ThreadLocal holder = ThreadLocal.withInitial(() -> DataSources.MASTER);
        public static DataSources get() { return holder.get(); }
        public static void set(DataSources ds) { holder.set(ds); }
        public static void reset() { holder.set(DataSources.MASTER); }
    }
  3. 路由 DataSource 繼承 AbstractRoutingDataSource:
    public class DynamicRoutingDataSource extends AbstractRoutingDataSource {
        @Override protected Object determineCurrentLookupKey() {
            return DataSourceTypeManager.get();
        }
    }
  4. Spring XML 注入 Master/Slave 到路由器:
    <bean id="dataSource" class="DynamicRoutingDataSource">
        <property name="defaultTargetDataSource" ref="dataSourceMaster"/>
        <property name="targetDataSources">
            <map key-type="DataSources">
                <entry key="MASTER" value-ref="dataSourceMaster"/>
                <entry key="SLAVE" value-ref="dataSourceSlave"/>
            </map>
        </property>
    </bean>
    <bean id="sqlSessionFactory" class="SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource"/> ...
    </bean>
  5. AOP 切面在 Service 方法前切換標識:
    @Aspect @Component @Order(0) // 必須早於 @Transactional
    public class DataSourceRoutingAspect {
        @Pointcut("execution(public * com.xxx.service..*.query*(..))")
        public void slaveMethods() {}
        @Before("slaveMethods()")
        public void routeToSlave() { DataSourceTypeManager.set(DataSources.SLAVE); }
    
        @Pointcut("execution(public * com.xxx.service..*.save*(..)) || execution(* ..update*(..)) || execution(* ..delete*(..))")
        public void masterMethods() {}
        @Before("masterMethods()")
        public void routeToMaster() { DataSourceTypeManager.set(DataSources.MASTER); }
    }

    關鍵:@Order(0) 確保路由切面在事務切面(@Transactional)之前執行,拿到正確連接。

原理深度剖析:AbstractRoutingDataSource

  1. 實現 InitializingBean,afterPropertiesSet() 將 targetDataSources Map 轉換為 resolvedDataSources(Key 解析後)。
  2. getConnection() → determineTargetDataSource() → determineCurrentLookupKey()(子類實現,讀 ThreadLocal)→ 從 Map 獲取實際 DataSource → 返回連接。

擴展方向:高可用與負載均衡

  • Master HA:LVS/Keepalived 虛擬 IP,或路由器內建心跳檢測自動切換。
  • Slave 負載均衡:輪詢/權重演算法選擇 Slave,心跳剔除故障節點。
  • 均可通過擴展 DynamicRoutingDataSource 實現(內部維護可用節點列表、定時健康檢查線程)。

總結

AOP + AbstractRoutingDataSource 實現**零侵入、極致靈活**的多數據源路由,完美支撐主從讀寫分離、多租戶、分庫分表等進階場景。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved