Spring Boot + MyBatis-Plus 讀寫分離與多 Slave 負載均衡示例
一、項目結構
src/main/java/com/example/demo/
├── config/
│ ├── DataSourceConfig.java # 數據源配置
│ ├── MyBatisPlusConfig.java # MyBatis-Plus配置
├── constant/
│ ├── DataSourceType.java # 數據源類型枚舉
├── context/
│ ├── DataSourceContextHolder.java # 數據源上下文
├── aspect/
│ ├── DataSourceAspect.java # 注解驅動的數據源切換
│ ├── DataSourceRouteAspect.java # 自動路由的數據源切換
├── annotation/
│ ├── DataSource.java # 自定義數據源注解
├── loadbalancer/
│ ├── SlaveDataSourceLoadBalancer.java # 從庫負載均衡器
├── mapper/
│ ├── UserMapper.java # DAO接口
├── service/
│ ├── UserService.java # 服務接口
│ ├── impl/
│ └── UserServiceImpl.java # 服務實現
├── controller/
│ ├── UserController.java # 控制器
└── DemoApplication.java # 啟動類
二、核心代碼實現
(一)數據源類型枚舉
package com.example.demo.constant;public enum DataSourceType {MASTER,SLAVE_1,SLAVE_2,SLAVE_3
}
(二)數據源上下文
package com.example.demo.context;import com.example.demo.constant.DataSourceType;public class DataSourceContextHolder {private static final ThreadLocal<DataSourceType> contextHolder = new ThreadLocal<>();public static void setDataSource(DataSourceType type) {contextHolder.set(type);}public static DataSourceType getDataSource() {return contextHolder.get();}public static void clearDataSource() {contextHolder.remove();}
}
(三)動態數據源
package com.example.demo.config;import com.example.demo.context.DataSourceContextHolder;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;public class DynamicRoutingDataSource extends AbstractRoutingDataSource {@Overrideprotected Object determineCurrentLookupKey() {return DataSourceContextHolder.getDataSource();}
}
(四)數據源配置
package com.example.demo.config;import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder;
import com.example.demo.constant.DataSourceType;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;@Configuration
public class DataSourceConfig {@Primary@Bean(name = "masterDataSource")@ConfigurationProperties("spring.datasource.master")public DataSource masterDataSource() {return DruidDataSourceBuilder.create().build();}@Bean(name = "slave1DataSource")@ConfigurationProperties("spring.datasource.slave1")public DataSource slave1DataSource() {return DruidDataSourceBuilder.create().build();}@Bean(name = "slave2DataSource")@ConfigurationProperties("spring.datasource.slave2")public DataSource slave2DataSource() {return DruidDataSourceBuilder.create().build();}@Bean(name = "slave3DataSource")@ConfigurationProperties("spring.datasource.slave3")public DataSource slave3DataSource() {return DruidDataSourceBuilder.create().build();}@Beanpublic DataSource dynamicDataSource() {DynamicRoutingDataSource dynamicDataSource = new DynamicRoutingDataSource();dynamicDataSource.setDefaultTargetDataSource(masterDataSource());Map<Object, Object> targetDataSources = new HashMap<>();targetDataSources.put(DataSourceType.MASTER, masterDataSource());targetDataSources.put(