SpringBoot+mybatis-plus實(shí)現(xiàn)多數(shù)據(jù)源配置的詳細(xì)步驟
MyBatis-Plus 多數(shù)據(jù)源配置詳解
在日益復(fù)雜的業(yè)務(wù)場(chǎng)景中,單一數(shù)據(jù)源往往難以滿(mǎn)足微服務(wù)架構(gòu)下的多元化需求,例如數(shù)據(jù)庫(kù)的讀寫(xiě)分離、分庫(kù)分表、以及連接不同業(yè)務(wù)模塊的獨(dú)立數(shù)據(jù)庫(kù)等。MyBatis-Plus 作為一款廣受歡迎的持久層框架,通過(guò)其強(qiáng)大的擴(kuò)展性,為開(kāi)發(fā)者提供了靈活便捷的多數(shù)據(jù)源配置方案。
本文將詳細(xì)介紹兩種主流的 MyBatis-Plus 多數(shù)據(jù)源配置方式:一種是官方推薦且廣為使用的 dynamic-datasource-spring-boot-starter 插件,另一種是基于 AOP(面向切面編程)的手動(dòng)配置方案,以幫助開(kāi)發(fā)者根據(jù)項(xiàng)目需求做出最優(yōu)選擇。
推薦方案:使用dynamic-datasource-spring-boot-starter
dynamic-datasource-spring-boot-starter 是一個(gè)由 MyBatis-Plus 團(tuán)隊(duì)成員開(kāi)源的 Spring Boot 多數(shù)據(jù)源啟動(dòng)器,它提供了豐富的功能和簡(jiǎn)便的配置,是實(shí)現(xiàn)動(dòng)態(tài)數(shù)據(jù)源切換的首選方案。
核心特性:
- 數(shù)據(jù)源分組: 適用于讀寫(xiě)分離、一主多從等復(fù)雜場(chǎng)景。
- 多種切換方式: 支持注解、AOP以及編程方式的靈活切換。
- 動(dòng)態(tài)數(shù)據(jù)源: 支持項(xiàng)目啟動(dòng)后動(dòng)態(tài)地增加或移除數(shù)據(jù)源。
- 組件集成: 無(wú)縫集成 MyBatis-Plus、Quartz、ShardingSphere 等多種組件。
- 分布式事務(wù): 提供了基于 Seata 的分布式事務(wù)解決方案。
1. 引入依賴(lài)
根據(jù)您的 Spring Boot 版本,在 pom.xml 文件中引入相應(yīng)的依賴(lài):
Spring Boot 2.x:
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>dynamic-datasource-spring-boot-starter</artifactId>
<version>3.5.2</version> <!-- 請(qǐng)使用最新版本 -->
</dependency>
Spring Boot 3.x:
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>dynamic-datasource-spring-boot3-starter</artifactId>
<version>4.2.0</version> <!-- 請(qǐng)使用最新版本 -->
</dependency>
2. 配置文件application.yml
在配置文件中定義多個(gè)數(shù)據(jù)源,并指定主數(shù)據(jù)源。
spring:
datasource:
dynamic:
primary: master # 設(shè)置默認(rèn)的數(shù)據(jù)源
strict: false # 設(shè)置為true時(shí),未匹配到數(shù)據(jù)源會(huì)報(bào)錯(cuò),設(shè)置為false則使用默認(rèn)數(shù)據(jù)源
datasource:
master:
url: jdbc:mysql://localhost:3306/db_master?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai
username: root
password: password123
driver-class-name: com.mysql.cj.jdbc.Driver
slave_1:
url: jdbc:mysql://localhost:3306/db_slave1?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai
username: root
password: password123
driver-class-name: com.mysql.cj.jdbc.Driver
3. 數(shù)據(jù)源切換方式
a. 注解方式(@DS)
@DS 注解是切換數(shù)據(jù)源最便捷的方式,可以作用于類(lèi)或方法上。方法上的注解優(yōu)先級(jí)高于類(lèi)上的注解。
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
@DS("slave_1") // 指定使用slave_1數(shù)據(jù)源
@Override
public List<User> getSlaveUsers() {
return this.list();
}
@Override
public List<User> getMasterUsers() {
// 未使用@DS注解,將使用默認(rèn)的master數(shù)據(jù)源
return this.list();
}
}
b. 編程方式(手動(dòng)切換)
在某些復(fù)雜的業(yè)務(wù)場(chǎng)景下,需要在代碼中動(dòng)態(tài)決定使用哪個(gè)數(shù)據(jù)源,此時(shí)可以使用 DynamicDataSourceContextHolder 進(jìn)行手動(dòng)切換。
@Service
public class OrderServiceImpl implements OrderService {
@Autowired
private ProductService productService;
@Autowired
private StockService stockService;
public void createOrder(String productId, int amount) {
// 查詢(xún)商品信息,切換到slave數(shù)據(jù)源
DynamicDataSourceContextHolder.push("slave_1");
Product product = productService.getById(productId);
DynamicDataSourceContextHolder.clear(); // 每次使用后必須清空
// 扣減庫(kù)存,切換到master數(shù)據(jù)源
DynamicDataSourceContextHolder.push("master");
stockService.deduct(productId, amount);
DynamicDataSourceContextHolder.clear();
// ... 創(chuàng)建訂單等操作,使用默認(rèn)數(shù)據(jù)源
}
}
手動(dòng)配置方案:基于 AOP 實(shí)現(xiàn)
對(duì)于希望擁有更高自由度或不愿引入額外依賴(lài)的開(kāi)發(fā)者,可以采用自定義注解和 AOP 的方式手動(dòng)實(shí)現(xiàn)動(dòng)態(tài)數(shù)據(jù)源切換。其核心原理是利用 Spring 提供的 AbstractRoutingDataSource 類(lèi)。
1. 添加 AOP 依賴(lài)
在 pom.xml 中確保已引入 AOP 相關(guān)依賴(lài):
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
2. 自定義數(shù)據(jù)源注解
創(chuàng)建一個(gè)注解,用于在需要切換數(shù)據(jù)源的方法上進(jìn)行標(biāo)識(shí)。
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DataSource {
String value();
}
3. 創(chuàng)建動(dòng)態(tài)數(shù)據(jù)源上下文
使用 ThreadLocal 存儲(chǔ)當(dāng)前線(xiàn)程需要使用的數(shù)據(jù)源名稱(chēng),以確保線(xiàn)程安全。
public class DynamicDataSourceContextHolder {
private static final ThreadLocal<String> CONTEXT_HOLDER = new ThreadLocal<>();
public static void setDataSourceKey(String key) {
CONTEXT_HOLDER.set(key);
}
public static String getDataSourceKey() {
return CONTEXT_HOLDER.get();
}
public static void clearDataSourceKey() {
CONTEXT_HOLDER.remove();
}
}
4. 實(shí)現(xiàn)AbstractRoutingDataSource
這是實(shí)現(xiàn)動(dòng)態(tài)數(shù)據(jù)源的核心,通過(guò)重寫(xiě) determineCurrentLookupKey 方法,從 DynamicDataSourceContextHolder 中獲取當(dāng)前數(shù)據(jù)源的 key。
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
public class DynamicDataSource extends AbstractRoutingDataSource {
@Override
protected Object determineCurrentLookupKey() {
return DynamicDataSourceContextHolder.getDataSourceKey();
}
}
5. 配置數(shù)據(jù)源
通過(guò) Java Config 的方式配置多個(gè)數(shù)據(jù)源,并將它們注入到 DynamicDataSource 中。
@Configuration
public class DataSourceConfig {
@Bean
@ConfigurationProperties("spring.datasource.master")
public DataSource masterDataSource() {
return DataSourceBuilder.create().build();
}
@Bean
@ConfigurationProperties("spring.datasource.slave")
public DataSource slaveDataSource() {
return DataSourceBuilder.create().build();
}
@Bean
@Primary
public DynamicDataSource dataSource(DataSource masterDataSource, DataSource slaveDataSource) {
Map<Object, Object> targetDataSources = new HashMap<>();
targetDataSources.put("master", masterDataSource);
targetDataSources.put("slave", slaveDataSource);
DynamicDataSource dataSource = new DynamicDataSource();
dataSource.setTargetDataSources(targetDataSources);
dataSource.setDefaultTargetDataSource(masterDataSource);
return dataSource;
}
}
并在 application.yml 中配置相應(yīng)的數(shù)據(jù)源信息:
spring:
datasource:
master:
url: jdbc:mysql://localhost:3306/db_master...
# ...
slave:
url: jdbc:mysql://localhost:3306/db_slave1...
# ...
6. 編寫(xiě) AOP 切面
創(chuàng)建切面,攔截帶有 @DataSource 注解的方法,在方法執(zhí)行前后設(shè)置和清除數(shù)據(jù)源 key。
@Aspect
@Component
public class DataSourceAspect {
@Pointcut("@annotation(com.example.annotation.DataSource)")
public void dataSourcePointCut() {
}
@Around("dataSourcePointCut()")
public Object around(ProceedingJoinPoint point) throws Throwable {
MethodSignature signature = (MethodSignature) point.getSignature();
Method method = signature.getMethod();
DataSource dataSource = method.getAnnotation(DataSource.class);
if (dataSource != null) {
DynamicDataSourceContextHolder.setDataSourceKey(dataSource.value());
}
try {
return point.proceed();
} finally {
DynamicDataSourceContextHolder.clearDataSourceKey();
}
}
}
方案對(duì)比與選擇
| 特性 | dynamic-datasource-spring-boot-starter | 手動(dòng)配置 AOP |
|---|---|---|
| 易用性 | 高,開(kāi)箱即用,配置簡(jiǎn)單。 | 中,需要手動(dòng)編寫(xiě)較多代碼。 |
| 功能豐富度 | 高,支持分組、動(dòng)態(tài)數(shù)據(jù)源、分布式事務(wù)等。 | 低,僅實(shí)現(xiàn)基礎(chǔ)的切換功能。 |
| 靈活性 | 高,支持多種切換方式。 | 高,完全自定義實(shí)現(xiàn),可控性強(qiáng)。 |
| 依賴(lài) | 引入額外 starter 依賴(lài)。 | 無(wú)需額外依賴(lài),更為輕量。 |
選擇建議:
- 對(duì)于絕大多數(shù)項(xiàng)目,特別是追求開(kāi)發(fā)效率和穩(wěn)定性的團(tuán)隊(duì),強(qiáng)烈推薦使用
dynamic-datasource-spring-boot-starter。 - 如果項(xiàng)目對(duì)依賴(lài)有嚴(yán)格控制,或需要實(shí)現(xiàn)高度定制化的數(shù)據(jù)源切換邏輯,可以選擇 手動(dòng)配置 AOP 的方式。
注意事項(xiàng)
- 事務(wù)管理: 在多數(shù)據(jù)源環(huán)境下,需要特別注意事務(wù)的一致性。對(duì)于單個(gè)數(shù)據(jù)源內(nèi)的事務(wù),Spring 的
@Transactional依然有效。但對(duì)于跨多個(gè)數(shù)據(jù)源的分布式事務(wù),則需要引入如 Seata 等分布式事務(wù)解決方案。 - AOP順序: 如果同時(shí)使用了
@Transactional和@DS注解,需要注意 AOP 的執(zhí)行順序,確保數(shù)據(jù)源切換在事務(wù)開(kāi)啟之前執(zhí)行。
通過(guò)以上兩種方案的介紹,開(kāi)發(fā)者可以根據(jù)自身項(xiàng)目的實(shí)際需求和團(tuán)隊(duì)的技術(shù)棧,選擇最合適的方式來(lái)配置和管理 MyBatis-Plus 的多數(shù)據(jù)源,從而構(gòu)建出更加健壯和可擴(kuò)展的應(yīng)用系統(tǒng)。
到此這篇關(guān)于SpringBoot+mybatis-plus實(shí)現(xiàn)多數(shù)據(jù)源配置的詳細(xì)步驟的文章就介紹到這了,更多相關(guān)SpringBoot mybatis-plus多數(shù)據(jù)源配置內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- SpringBoot項(xiàng)目中多數(shù)據(jù)源配置方法與使用場(chǎng)景
- SpringBoot進(jìn)行多數(shù)據(jù)源配置的詳細(xì)步驟
- SpringBoot多數(shù)據(jù)源配置完整指南
- Mybatis+Druid+MybatisPlus多數(shù)據(jù)源配置方法
- Mybatis-plus配置多數(shù)據(jù)源,連接多數(shù)據(jù)庫(kù)方式
- SpringBoot中配置多數(shù)據(jù)源的方法詳解
- springboot配置多數(shù)據(jù)源(靜態(tài)和動(dòng)態(tài)數(shù)據(jù)源)
相關(guān)文章
Java常用流程控制語(yǔ)句實(shí)現(xiàn)原理解析
這篇文章主要介紹了Java常用流程控制語(yǔ)句實(shí)現(xiàn)原理解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-08-08
基于Spring概念模型:PathMatcher 路徑匹配器
這篇文章主要介紹了Spring概念模型:PathMatcher 路徑匹配器,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-09-09
SpringCloud引入feign失敗或找不到@EnableFeignClients注解問(wèn)題
這篇文章主要介紹了SpringCloud引入feign失敗或找不到@EnableFeignClients注解問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-03-03
SpringBoot如何引入緩存提高單次查詢(xún)數(shù)據(jù)效率
這篇文章主要介紹了SpringBoot如何引入緩存提高單次查詢(xún)數(shù)據(jù)效率問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-01-01
SpringBoot中application.yml基本配置解讀
文章主要介紹了Spring Boot項(xiàng)目中`application.properties`和`application.yml`配置文件的使用方法和區(qū)別,包括優(yōu)先級(jí)、配置文件所在目錄、端口服務(wù)配置、數(shù)據(jù)庫(kù)配置、多profile配置以及靜態(tài)資源路徑的指定2024-12-12
Netty中ChannelPoolHandler調(diào)用處理程序詳解
這篇文章主要介紹了Netty中ChannelPoolHandler調(diào)用處理程序詳解,Netty 是基于 Java NIO 的異步事件驅(qū)動(dòng)的網(wǎng)絡(luò)應(yīng)用框架,使用 Netty 可以快速開(kāi)發(fā)網(wǎng)絡(luò)應(yīng)用,Netty 提供了高層次的抽象來(lái)簡(jiǎn)化 TCP 和 UDP 服務(wù)器的編程,但是你仍然可以使用底層的 API,需要的朋友可以參考下2023-11-11
java8新特性將List中按指定屬性排序過(guò)濾重復(fù)數(shù)據(jù)的方法
這篇文章主要介紹了java8新特性將List中按指定屬性排序過(guò)濾重復(fù)數(shù)據(jù)的方法,非常不錯(cuò),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2019-08-08

