tacit/mybatis-plus-multi-datasour...

337 lines
10 KiB
Markdown
Raw Normal View History

# MyBatis Plus 多数据源配置与使用文档
## 1. 环境与依赖
### 1.1 环境要求
- Spring Boot 3.x
- MyBatis Plus 3.5.x
- Java 21
### 1.2 依赖添加
添加 MyBatis Plus 动态数据源依赖:
```xml
<!-- Dynamic Datasource -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>dynamic-datasource-spring-boot-starter</artifactId>
<version>3.6.1</version>
</dependency>
```
## 2. 配置文件修改
### 2.1 主配置文件
配置多数据源:
```yaml
spring:
datasource:
dynamic:
primary: master
strict: false
datasource:
master:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://117.72.94.232:53306/tacit?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
username: root
password: fU44GFH5
slave:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/tacit?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
username: root
password: root123
```
### 2.2 配置说明
| 配置项 | 说明 | 示例值 |
|-------|------|-------|
| primary | 默认数据源名称 | master |
| strict | 是否启用严格模式 | false |
| datasource.master | 主数据源配置 | - |
| datasource.slave | 从数据源配置 | - |
| driver-class-name | 数据库驱动类名 | com.mysql.cj.jdbc.Driver |
| url | 数据库连接地址 | jdbc:mysql://117.72.94.232:53306/tacit |
| username | 数据库用户名 | root |
| password | 数据库密码 | password |
## 3. 代码实现
### 3.1 实体类
创建测试实体类 `TestEntity`
```java
package com.tacit.admin.entity;
import com.baomidou.mybatisplus.annotation.TableName;
import com.tacit.common.entity.Base;
import lombok.Data;
import lombok.EqualsAndHashCode;
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("test") // 指定数据库表名
public class TestEntity extends Base {
@TableId(type = IdType.AUTO)
private Long id;
private String name; // 姓名
private Integer age; // 年龄
private String email; // 邮箱
}
```
### 3.2 Mapper 接口
创建 Mapper 接口 `TestMapper`
```java
package com.tacit.admin.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.tacit.admin.entity.TestEntity;
import org.apache.ibatis.annotations.Mapper;
@Mapper // 标记为 MyBatis Mapper 接口
public interface TestMapper extends BaseMapper<TestEntity> {
// 继承 BaseMapper 后,自动拥有 CRUD 方法
}
```
### 3.3 Service 接口
创建 Service 接口 `TestService`
```java
package com.tacit.admin.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.tacit.admin.entity.TestEntity;
public interface TestService extends IService<TestEntity> {
/**
* 根据 ID 查询测试数据
* @param id 主键 ID
* @return TestEntity
*/
TestEntity getTestById(Long id);
}
```
### 3.4 Service 实现类
#### 3.4.1 主数据源实现类
创建主数据源 Service 实现类 `TestMasterServiceImpl`
```java
package com.tacit.admin.service.impl;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.tacit.admin.entity.TestEntity;
import com.tacit.admin.mapper.TestMapper;
import com.tacit.admin.service.TestService;
import org.springframework.stereotype.Service;
@Service("testMasterService") // 指定 Bean 名称,方便注入
@DS("master") // 指定使用主数据源
public class TestMasterServiceImpl extends ServiceImpl<TestMapper, TestEntity> implements TestService {
/**
* 使用主数据源查询数据
* @param id 主键 ID
* @return TestEntity
*/
@Override
public TestEntity getTestById(Long id) {
return getById(id); // 调用父类方法,自动使用主数据源
}
}
```
#### 3.4.2 从数据源实现类
创建从数据源 Service 实现类 `TestSlaveServiceImpl`
```java
package com.tacit.admin.service.impl;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.tacit.admin.entity.TestEntity;
import com.tacit.admin.mapper.TestMapper;
import com.tacit.admin.service.TestService;
import org.springframework.stereotype.Service;
@Service("testSlaveService") // 指定 Bean 名称,方便注入
@DS("slave") // 指定使用从数据源
public class TestSlaveServiceImpl extends ServiceImpl<TestMapper, TestEntity> implements TestService {
/**
* 使用从数据源查询数据
* @param id 主键 ID
* @return TestEntity
*/
@Override
public TestEntity getTestById(Long id) {
return getById(id); // 调用父类方法,自动使用从数据源
}
}
```
### 3.5 控制器
创建测试控制器 `MultiDatasourceTestController`
```java
package com.tacit.admin.controller;
import com.tacit.common.entity.ResponseResult;
import com.tacit.admin.entity.TestEntity;
import com.tacit.admin.service.TestService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/multi-datasource")
@Tag(name = "多数据源测试接口", description = "用于测试多数据源的接口")
public class MultiDatasourceTestController {
@Autowired
@Qualifier("testMasterService") // 注入主数据源 Service
private TestService testMasterService;
@Autowired
@Qualifier("testSlaveService") // 注入从数据源 Service
private TestService testSlaveService;
@Operation(summary = "使用主数据源创建测试数据", description = "使用主数据源创建测试数据")
@PostMapping("/master/create")
public ResponseResult<TestEntity> createTestDataWithMaster(@RequestBody TestEntity testEntity) {
testMasterService.save(testEntity); // 使用主数据源保存数据
return ResponseResult.success(testEntity);
}
@Operation(summary = "使用主数据源查询测试数据", description = "使用主数据源查询测试数据")
@GetMapping("/master/{id}")
public ResponseResult<TestEntity> getTestDataWithMaster(@PathVariable Long id) {
return ResponseResult.success(testMasterService.getTestById(id)); // 使用主数据源查询数据
}
@Operation(summary = "使用从数据源查询测试数据", description = "使用从数据源查询测试数据")
@GetMapping("/slave/{id}")
public ResponseResult<TestEntity> getTestDataWithSlave(@PathVariable Long id) {
return ResponseResult.success(testSlaveService.getTestById(id)); // 使用从数据源查询数据
}
}
```
## 4. 使用方法
### 4.1 注解方式
使用 `@DS` 注解可以指定方法或类使用的数据源:
```java
// 类级别:整个类的方法都使用 master 数据源
@Service
@DS("master")
public class TestServiceImpl {
// ...
}
// 方法级别:该方法使用 slave 数据源(优先级高于类级别)
@DS("slave")
public TestEntity getTestById(Long id) {
return getById(id);
}
```
### 4.2 动态数据源名称
支持从方法参数或上下文中获取动态数据源名称:
```java
// 从方法参数中获取数据源名称
@DS("#datasourceName")
public TestEntity getTestById(Long id, String datasourceName) {
return getById(id);
}
// 从上下文或SpEL表达式中获取数据源名称
@DS("#{@systemConfig.getDatasourceName()}")
public TestEntity getTestById(Long id) {
return getById(id);
}
```
### 4.3 数据源优先级
数据源的优先级顺序为:
1. 方法上的 `@DS` 注解
2. 类上的 `@DS` 注解
3. 全局默认数据源primary
注意Service 层的 @DS 注解具有更高优先级
## 5. 测试验证
### 5.1 编译测试
运行以下命令编译项目,确保配置正确:
```bash
cd d:\workSpace\tacit; mvn clean compile -pl tacit-admin -am
```
### 5.2 运行测试
启动项目后,通过以下方式测试多数据源:
1. **使用主数据源创建数据**
```bash
POST /multi-datasource/master/create
Content-Type: application/json
{
"name": "测试用户",
"age": 25,
"email": "test@example.com"
}
```
2. **使用主数据源查询数据**
```bash
GET /multi-datasource/master/1
```
3. **使用从数据源查询数据**
```bash
GET /multi-datasource/slave/1
```
## 6. 注意事项
1. **依赖冲突**:确保项目中没有其他数据源相关的依赖冲突,如 `spring-boot-starter-jdbc` 或其他动态数据源框架。
2. **数据源名称**:数据源名称必须与配置文件中的名称一致,大小写敏感。
3. **事务管理**:多数据源环境下,事务管理需要特别注意,建议使用 `@DSTransactional` 注解替代 `@Transactional` 注解。
4. **严格模式**:生产环境建议开启严格模式(`strict: true`),确保数据源名称正确。
5. **性能考虑**:频繁切换数据源会带来性能开销,建议根据业务场景合理设计数据源使用策略。
6. **配置中心**:如果使用配置中心(如 Nacos可以将数据源配置迁移到配置中心便于动态调整。
## 7. 常见问题
### 7.1 数据源切换不生效
- 检查 `@DS` 注解是否正确添加到方法或类上
- 检查数据源名称是否与配置文件一致
- 检查是否开启了严格模式,以及默认数据源是否配置正确
### 7.2 事务不生效
- 使用 `@DSTransactional` 注解替代 `@Transactional` 注解
- 确保事务方法是 `public` 修饰的
- 确保事务方法不是通过内部调用的Spring AOP 代理机制)