From a85a68e8b0d3893ed3d8b42fa117a8264cec9159 Mon Sep 17 00:00:00 2001 From: panxuejie <15855548138@163.com> Date: Wed, 14 Jan 2026 09:26:37 +0800 Subject: [PATCH] =?UTF-8?q?feat:=E4=BF=AE=E6=94=B9=E9=85=8D=E7=BD=AE?= =?UTF-8?q?=E6=96=87=E4=BB=B6=E6=96=B9=E5=BC=8F,=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=E5=A4=9A=E6=95=B0=E6=8D=AE=E6=BA=90=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mybatis-plus-multi-datasource.md | 336 ++++++++++++++++++ pom.xml | 7 - tacit-admin/pom.xml | 18 +- .../MethodLevelDSTestController.java | 86 +++++ .../MultiDatasourceTestController.java | 48 +++ .../com/tacit/admin/entity/TestEntity.java | 19 + .../com/tacit/admin/mapper/TestMapper.java | 18 + .../service/MethodLevelDSTestService.java | 69 ++++ .../com/tacit/admin/service/TestService.java | 8 + .../impl/MethodLevelDSTestServiceImpl.java | 124 +++++++ .../service/impl/TestMasterServiceImpl.java | 17 + .../service/impl/TestSlaveServiceImpl.java | 17 + .../src/main/resources/application-dev.yml | 19 +- .../src/main/resources/application-qa.yml | 19 +- .../src/main/resources/application.yml | 2 + tacit-admin/src/main/resources/bootstrap.yml | 18 - .../src/main/resources/mapper/TestMapper.xml | 19 + .../src/main/resources/tacit-admin.yaml | 30 -- tacit-app-api/pom.xml | 5 - .../src/main/resources/application-dev.yml | 18 +- .../src/main/resources/application-qa.yml | 18 +- .../src/main/resources/application.yml | 2 + .../src/main/resources/bootstrap.yml | 18 - tacit-gateway/pom.xml | 6 - .../src/main/resources/application-dev.yml | 18 +- .../src/main/resources/application-qa.yml | 18 +- .../src/main/resources/application.yml | 4 + .../src/main/resources/bootstrap.yml | 21 -- 28 files changed, 872 insertions(+), 130 deletions(-) create mode 100644 mybatis-plus-multi-datasource.md create mode 100644 tacit-admin/src/main/java/com/tacit/admin/controller/MethodLevelDSTestController.java create mode 100644 tacit-admin/src/main/java/com/tacit/admin/controller/MultiDatasourceTestController.java create mode 100644 tacit-admin/src/main/java/com/tacit/admin/entity/TestEntity.java create mode 100644 tacit-admin/src/main/java/com/tacit/admin/mapper/TestMapper.java create mode 100644 tacit-admin/src/main/java/com/tacit/admin/service/MethodLevelDSTestService.java create mode 100644 tacit-admin/src/main/java/com/tacit/admin/service/TestService.java create mode 100644 tacit-admin/src/main/java/com/tacit/admin/service/impl/MethodLevelDSTestServiceImpl.java create mode 100644 tacit-admin/src/main/java/com/tacit/admin/service/impl/TestMasterServiceImpl.java create mode 100644 tacit-admin/src/main/java/com/tacit/admin/service/impl/TestSlaveServiceImpl.java delete mode 100644 tacit-admin/src/main/resources/bootstrap.yml create mode 100644 tacit-admin/src/main/resources/mapper/TestMapper.xml delete mode 100644 tacit-admin/src/main/resources/tacit-admin.yaml delete mode 100644 tacit-app-api/src/main/resources/bootstrap.yml delete mode 100644 tacit-gateway/src/main/resources/bootstrap.yml diff --git a/mybatis-plus-multi-datasource.md b/mybatis-plus-multi-datasource.md new file mode 100644 index 0000000..3dc7279 --- /dev/null +++ b/mybatis-plus-multi-datasource.md @@ -0,0 +1,336 @@ +# MyBatis Plus 多数据源配置与使用文档 + +## 1. 环境与依赖 + +### 1.1 环境要求 +- Spring Boot 3.x +- MyBatis Plus 3.5.x +- Java 21 + +### 1.2 依赖添加 +添加 MyBatis Plus 动态数据源依赖: + +```xml + + + com.baomidou + dynamic-datasource-spring-boot-starter + 3.6.1 + +``` + +## 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 { + // 继承 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 { + /** + * 根据 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 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 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 createTestDataWithMaster(@RequestBody TestEntity testEntity) { + testMasterService.save(testEntity); // 使用主数据源保存数据 + return ResponseResult.success(testEntity); + } + + @Operation(summary = "使用主数据源查询测试数据", description = "使用主数据源查询测试数据") + @GetMapping("/master/{id}") + public ResponseResult getTestDataWithMaster(@PathVariable Long id) { + return ResponseResult.success(testMasterService.getTestById(id)); // 使用主数据源查询数据 + } + + @Operation(summary = "使用从数据源查询测试数据", description = "使用从数据源查询测试数据") + @GetMapping("/slave/{id}") + public ResponseResult 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 代理机制) + + diff --git a/pom.xml b/pom.xml index 62d7568..ca84e6a 100644 --- a/pom.xml +++ b/pom.xml @@ -134,13 +134,6 @@ ${nacos-client.version} - - - org.springframework.cloud - spring-cloud-starter-bootstrap - 4.0.4 - - org.springdoc diff --git a/tacit-admin/pom.xml b/tacit-admin/pom.xml index f9d1561..94efb23 100644 --- a/tacit-admin/pom.xml +++ b/tacit-admin/pom.xml @@ -41,17 +41,18 @@ com.baomidou mybatis-plus-boot-starter + + + + com.baomidou + dynamic-datasource-spring-boot-starter + 3.6.1 + - com.mysql mysql-connector-j - runtime @@ -94,11 +95,6 @@ resilience4j-spring-boot3 - - - org.springframework.cloud - spring-cloud-starter-bootstrap - diff --git a/tacit-admin/src/main/java/com/tacit/admin/controller/MethodLevelDSTestController.java b/tacit-admin/src/main/java/com/tacit/admin/controller/MethodLevelDSTestController.java new file mode 100644 index 0000000..ea7c9f9 --- /dev/null +++ b/tacit-admin/src/main/java/com/tacit/admin/controller/MethodLevelDSTestController.java @@ -0,0 +1,86 @@ +package com.tacit.admin.controller; + +import com.tacit.common.entity.ResponseResult; +import com.tacit.admin.entity.TestEntity; +import com.tacit.admin.service.MethodLevelDSTestService; +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.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.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +/** + * 方法级 @DS 注解使用样例 - 控制器 + * 演示不同场景下的方法级数据源切换 + */ +@RestController +@RequestMapping("/test") +@Tag(name = "方法级 @DS 注解测试接口", description = "用于测试方法级 @DS 注解的接口") +public class MethodLevelDSTestController { + + @Autowired + private MethodLevelDSTestService methodLevelDSTestService; + + @Operation(summary = "示例1:保存到主数据源", description = "使用 @DS(\"master\") 指定使用主数据源") + @PostMapping("/save-to-master") + public ResponseResult saveToMaster(@RequestBody TestEntity testEntity) { + boolean result = methodLevelDSTestService.saveToMaster(testEntity); + return ResponseResult.success(result); + } + + @Operation(summary = "示例2:从从数据源查询", description = "使用 @DS(\"slave\") 指定使用从数据源") + @GetMapping("/get-from-slave/{id}") + public ResponseResult getFromSlave(@PathVariable Long id) { + TestEntity result = methodLevelDSTestService.getFromSlave(id); + return ResponseResult.success(result); + } + + @Operation(summary = "示例3:动态数据源名称", description = "使用 @DS(\"#datasourceName\") 从方法参数中获取数据源名称") + @PostMapping("/save-to-dynamic") + public ResponseResult saveToDynamicDatasource(@RequestBody TestEntity testEntity, + @RequestParam String datasourceName) { + boolean result = methodLevelDSTestService.saveToDynamicDatasource(testEntity, datasourceName); + return ResponseResult.success(result); + } + + @Operation(summary = "示例4:结合事务使用", description = "使用 @DSTransactional 注解支持多数据源事务") + @PostMapping("/save-with-transaction") + public ResponseResult saveWithTransaction(@RequestBody TestEntity testEntity) { + boolean result = methodLevelDSTestService.saveWithTransaction(testEntity); + return ResponseResult.success(result); + } + + @Operation(summary = "示例5-1:从主数据源查询", description = "同一个类中不同方法使用不同数据源 - 从主数据源查询") + @GetMapping("/get-from-master/{id}") + public ResponseResult getFromMaster(@PathVariable Long id) { + TestEntity result = methodLevelDSTestService.getFromMaster(id); + return ResponseResult.success(result); + } + + @Operation(summary = "示例5-2:从从数据源查询", description = "同一个类中不同方法使用不同数据源 - 从从数据源查询") + @GetMapping("/get-from-slave-db/{id}") + public ResponseResult getFromSlaveDB(@PathVariable Long id) { + TestEntity result = methodLevelDSTestService.getFromSlaveDB(id); + return ResponseResult.success(result); + } + + @Operation(summary = "示例6:使用默认数据源", description = "不使用 @DS 注解,使用全局默认数据源(primary)") + @GetMapping("/get-from-default/{id}") + public ResponseResult getFromDefault(@PathVariable Long id) { + TestEntity result = methodLevelDSTestService.getFromDefault(id); + return ResponseResult.success(result); + } + + + @Operation(summary = "示例7:获取mapper方法级数据源切换", description = "传入数据源") + @GetMapping("/get-one/{datasourceName}") + public ResponseResult getFromDefault(@PathVariable String datasourceName) { + TestEntity result = methodLevelDSTestService.getOneTest(datasourceName); + return ResponseResult.success(result); + } +} \ No newline at end of file diff --git a/tacit-admin/src/main/java/com/tacit/admin/controller/MultiDatasourceTestController.java b/tacit-admin/src/main/java/com/tacit/admin/controller/MultiDatasourceTestController.java new file mode 100644 index 0000000..e7e4c5d --- /dev/null +++ b/tacit-admin/src/main/java/com/tacit/admin/controller/MultiDatasourceTestController.java @@ -0,0 +1,48 @@ +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("/test") +@Tag(name = "多数据源测试接口", description = "用于测试多数据源的接口") +public class MultiDatasourceTestController { + + @Autowired + @Qualifier("testMasterService") + private TestService testMasterService; + + @Autowired + @Qualifier("testSlaveService") + private TestService testSlaveService; + + @Operation(summary = "使用主数据源创建测试数据", description = "使用主数据源创建测试数据") + @PostMapping("/master/create") + public ResponseResult createTestDataWithMaster(@RequestBody TestEntity testEntity) { + testMasterService.save(testEntity); + return ResponseResult.success(testEntity); + } + + @Operation(summary = "使用主数据源查询测试数据", description = "使用主数据源查询测试数据") + @GetMapping("/master/{id}") + public ResponseResult getTestDataWithMaster(@PathVariable Long id) { + return ResponseResult.success(testMasterService.getTestById(id)); + } + + @Operation(summary = "使用从数据源查询测试数据", description = "使用从数据源查询测试数据") + @GetMapping("/slave/{id}") + public ResponseResult getTestDataWithSlave(@PathVariable Long id) { + return ResponseResult.success(testSlaveService.getTestById(id)); + } +} \ No newline at end of file diff --git a/tacit-admin/src/main/java/com/tacit/admin/entity/TestEntity.java b/tacit-admin/src/main/java/com/tacit/admin/entity/TestEntity.java new file mode 100644 index 0000000..5cfc4e1 --- /dev/null +++ b/tacit-admin/src/main/java/com/tacit/admin/entity/TestEntity.java @@ -0,0 +1,19 @@ +package com.tacit.admin.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.tacit.common.entity.Base; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.springframework.data.annotation.Id; + +@Data +@TableName("test") +public class TestEntity{ + @TableId(type = IdType.AUTO) + private Long id; + private String name; + private Integer age; + private String email; +} \ No newline at end of file diff --git a/tacit-admin/src/main/java/com/tacit/admin/mapper/TestMapper.java b/tacit-admin/src/main/java/com/tacit/admin/mapper/TestMapper.java new file mode 100644 index 0000000..f0899f3 --- /dev/null +++ b/tacit-admin/src/main/java/com/tacit/admin/mapper/TestMapper.java @@ -0,0 +1,18 @@ +package com.tacit.admin.mapper; + +import com.baomidou.dynamic.datasource.annotation.DS; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.tacit.admin.entity.TestEntity; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface TestMapper extends BaseMapper { + + @DS("master") + TestEntity getOneTestMaster(); + + @DS("slave") + TestEntity getOneTestSlave(); + + TestEntity getOneTest(); +} \ No newline at end of file diff --git a/tacit-admin/src/main/java/com/tacit/admin/service/MethodLevelDSTestService.java b/tacit-admin/src/main/java/com/tacit/admin/service/MethodLevelDSTestService.java new file mode 100644 index 0000000..f9ce62e --- /dev/null +++ b/tacit-admin/src/main/java/com/tacit/admin/service/MethodLevelDSTestService.java @@ -0,0 +1,69 @@ +package com.tacit.admin.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.tacit.admin.entity.TestEntity; + +/** + * 方法级 @DS 注解使用样例 - Service 接口 + * 定义方法级数据源切换的服务方法 + */ +public interface MethodLevelDSTestService extends IService { + + /** + * 示例1:基本的方法级数据源切换 - 保存到主数据源 + * @param testEntity 测试实体 + * @return 保存结果 + */ + boolean saveToMaster(TestEntity testEntity); + + /** + * 示例2:基本的方法级数据源切换 - 从从数据源查询 + * @param id 主键ID + * @return 查询结果 + */ + TestEntity getFromSlave(Long id); + + /** + * 示例3:动态数据源名称 - 从方法参数中获取数据源名称 + * @param testEntity 测试实体 + * @param datasourceName 数据源名称 + * @return 保存结果 + */ + boolean saveToDynamicDatasource(TestEntity testEntity, String datasourceName); + + /** + * 示例4:结合事务使用 - 支持多数据源事务 + * @param testEntity 测试实体 + * @return 保存结果 + */ + boolean saveWithTransaction(TestEntity testEntity); + + /** + * 示例5:同一个类中不同方法使用不同数据源 - 从主数据源查询 + * @param id 主键ID + * @return 查询结果 + */ + TestEntity getFromMaster(Long id); + + /** + * 示例5:同一个类中不同方法使用不同数据源 - 从从数据源查询 + * @param id 主键ID + * @return 查询结果 + */ + TestEntity getFromSlaveDB(Long id); + + /** + * 示例6:默认数据源 - 使用全局默认数据源 + * @param id 主键ID + * @return 查询结果 + */ + TestEntity getFromDefault(Long id); + + /** + * 示例7:获取mapper方法级数据源切换 + * @param datasourceName 数据源名称 + * @return 测试结果 + */ + TestEntity getOneTest(String datasourceName); + +} \ No newline at end of file diff --git a/tacit-admin/src/main/java/com/tacit/admin/service/TestService.java b/tacit-admin/src/main/java/com/tacit/admin/service/TestService.java new file mode 100644 index 0000000..21ebb10 --- /dev/null +++ b/tacit-admin/src/main/java/com/tacit/admin/service/TestService.java @@ -0,0 +1,8 @@ +package com.tacit.admin.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.tacit.admin.entity.TestEntity; + +public interface TestService extends IService { + TestEntity getTestById(Long id); +} \ No newline at end of file diff --git a/tacit-admin/src/main/java/com/tacit/admin/service/impl/MethodLevelDSTestServiceImpl.java b/tacit-admin/src/main/java/com/tacit/admin/service/impl/MethodLevelDSTestServiceImpl.java new file mode 100644 index 0000000..8261000 --- /dev/null +++ b/tacit-admin/src/main/java/com/tacit/admin/service/impl/MethodLevelDSTestServiceImpl.java @@ -0,0 +1,124 @@ +package com.tacit.admin.service.impl; + +import com.baomidou.dynamic.datasource.annotation.DS; +import com.baomidou.dynamic.datasource.annotation.DSTransactional; +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.MethodLevelDSTestService; +import org.springframework.stereotype.Service; + +/** + * 方法级 @DS 注解使用样例 + * 展示不同场景下的方法级数据源切换 + */ +@Service +public class MethodLevelDSTestServiceImpl extends ServiceImpl implements MethodLevelDSTestService { + + /** + * 示例1:基本的方法级数据源切换 + * 使用 @DS("master") 指定使用主数据源 + * @param testEntity 测试实体 + * @return 保存结果 + */ + @DS("master") + @Override + public boolean saveToMaster(TestEntity testEntity) { + return save(testEntity); + } + + /** + * 示例2:基本的方法级数据源切换 + * 使用 @DS("slave") 指定使用从数据源 + * @param id 主键ID + * @return 查询结果 + */ + @DS("slave") + @Override + public TestEntity getFromSlave(Long id) { + return getById(id); + } + + /** + * 示例3:动态数据源名称 + * 使用 @DS("#datasourceName") 从方法参数中获取数据源名称 + * @param testEntity 测试实体 + * @param datasourceName 数据源名称 + * @return 保存结果 + */ + @DS("#datasourceName") + @Override + public boolean saveToDynamicDatasource(TestEntity testEntity, String datasourceName) { + return save(testEntity); + } + + /** + * 示例4:结合事务使用 + * 使用 @DSTransactional 注解支持多数据源事务 + * @param testEntity 测试实体 + * @return 保存结果 + */ + @DS("master") + @DSTransactional + @Override + public boolean saveWithTransaction(TestEntity testEntity) { + // 保存数据 + boolean result = save(testEntity); + // 模拟业务逻辑 + if (result) { + // 可以在同一个事务中操作其他数据 + TestEntity anotherEntity = new TestEntity(); + anotherEntity.setName("关联数据"); + anotherEntity.setAge(30); + anotherEntity.setEmail("related@example.com"); + return save(anotherEntity); + } + return false; + } + + /** + * 示例5:同一个类中不同方法使用不同数据源 + * 方法1:使用主数据源 + * @param id 主键ID + * @return 查询结果 + */ + @DS("master") + @Override + public TestEntity getFromMaster(Long id) { + return getById(id); + } + + /** + * 示例5:同一个类中不同方法使用不同数据源 + * 方法2:使用从数据源 + * @param id 主键ID + * @return 查询结果 + */ + @DS("slave") + @Override + public TestEntity getFromSlaveDB(Long id) { + return getById(id); + } + + /** + * 示例6:默认数据源 + * 不使用 @DS 注解,使用全局默认数据源(primary) + * @param id 主键ID + * @return 查询结果 + */ + @Override + public TestEntity getFromDefault(Long id) { + return getById(id); + } + + @Override + public TestEntity getOneTest(String datasourceName) { + return switch (datasourceName) { + case "master" -> baseMapper.getOneTestMaster(); + case "slave" -> baseMapper.getOneTestSlave(); + default -> baseMapper.getOneTest(); + }; + } + + +} \ No newline at end of file diff --git a/tacit-admin/src/main/java/com/tacit/admin/service/impl/TestMasterServiceImpl.java b/tacit-admin/src/main/java/com/tacit/admin/service/impl/TestMasterServiceImpl.java new file mode 100644 index 0000000..8eff180 --- /dev/null +++ b/tacit-admin/src/main/java/com/tacit/admin/service/impl/TestMasterServiceImpl.java @@ -0,0 +1,17 @@ +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") +@DS("master") // 指定使用主数据源 +public class TestMasterServiceImpl extends ServiceImpl implements TestService { + @Override + public TestEntity getTestById(Long id) { + return getById(id); + } +} \ No newline at end of file diff --git a/tacit-admin/src/main/java/com/tacit/admin/service/impl/TestSlaveServiceImpl.java b/tacit-admin/src/main/java/com/tacit/admin/service/impl/TestSlaveServiceImpl.java new file mode 100644 index 0000000..803d473 --- /dev/null +++ b/tacit-admin/src/main/java/com/tacit/admin/service/impl/TestSlaveServiceImpl.java @@ -0,0 +1,17 @@ +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") +@DS("slave") // 指定使用从数据源 +public class TestSlaveServiceImpl extends ServiceImpl implements TestService { + @Override + public TestEntity getTestById(Long id) { + return getById(id); + } +} \ No newline at end of file diff --git a/tacit-admin/src/main/resources/application-dev.yml b/tacit-admin/src/main/resources/application-dev.yml index 67ff5c7..84e841b 100644 --- a/tacit-admin/src/main/resources/application-dev.yml +++ b/tacit-admin/src/main/resources/application-dev.yml @@ -1,3 +1,16 @@ -server: - port: 8082 - +spring: + config: + import: "optional:nacos:${spring.application.name}.yaml" + cloud: + nacos: + discovery: + server-addr: 117.72.94.232:9091 + username: nacos + password: nacos + namespace: dev + config: + server-addr: 117.72.94.232:9091 + file-extension: yaml + username: nacos + password: nacos + namespace: dev \ No newline at end of file diff --git a/tacit-admin/src/main/resources/application-qa.yml b/tacit-admin/src/main/resources/application-qa.yml index 67ff5c7..90606d1 100644 --- a/tacit-admin/src/main/resources/application-qa.yml +++ b/tacit-admin/src/main/resources/application-qa.yml @@ -1,3 +1,16 @@ -server: - port: 8082 - +spring: + config: + import: "optional:nacos:${spring.application.name}.yaml" + cloud: + nacos: + discovery: + server-addr: 117.72.94.232:9091 + username: nacos + password: nacos + namespace: ${nacos.namespace} + config: + server-addr: 117.72.94.232:9091 + file-extension: yaml + username: nacos + password: nacos + namespace: ${nacos.namespace} \ No newline at end of file diff --git a/tacit-admin/src/main/resources/application.yml b/tacit-admin/src/main/resources/application.yml index 3d7808a..6cf9270 100644 --- a/tacit-admin/src/main/resources/application.yml +++ b/tacit-admin/src/main/resources/application.yml @@ -1,3 +1,5 @@ spring: + application: + name: tacit-admin profiles: active: dev diff --git a/tacit-admin/src/main/resources/bootstrap.yml b/tacit-admin/src/main/resources/bootstrap.yml deleted file mode 100644 index eb7e6dd..0000000 --- a/tacit-admin/src/main/resources/bootstrap.yml +++ /dev/null @@ -1,18 +0,0 @@ -spring: - application: - name: tacit-admin - config: - import: "optional:nacos:${spring.application.name}.yaml" - cloud: - nacos: - discovery: - server-addr: ${nacos.server-addr:117.72.94.232:9091} - username: ${nacos.username:nacos} - password: ${nacos.password:nacos} - namespace: ${nacos.namespace:33140c53-3f57-4bd2-b9c8-f507581b6ca2} - config: - server-addr: ${nacos.server-addr:117.72.94.232:9091} - file-extension: yaml - username: ${nacos.username:nacos} - password: ${nacos.password:nacos} - namespace: ${nacos.namespace:33140c53-3f57-4bd2-b9c8-f507581b6ca2} \ No newline at end of file diff --git a/tacit-admin/src/main/resources/mapper/TestMapper.xml b/tacit-admin/src/main/resources/mapper/TestMapper.xml new file mode 100644 index 0000000..d229fe2 --- /dev/null +++ b/tacit-admin/src/main/resources/mapper/TestMapper.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/tacit-admin/src/main/resources/tacit-admin.yaml b/tacit-admin/src/main/resources/tacit-admin.yaml deleted file mode 100644 index 8437fe6..0000000 --- a/tacit-admin/src/main/resources/tacit-admin.yaml +++ /dev/null @@ -1,30 +0,0 @@ -server: - port: 8082 - -spring: - datasource: - driver-class-name: com.oceanbase.jdbc.Driver - url: jdbc:oceanbase://localhost:2881/tacit?useUnicode=true&characterEncoding=utf-8&useSSL=false - username: root - password: password - -mybatis-plus: - configuration: - map-underscore-to-camel-case: true - log-impl: org.apache.ibatis.logging.stdout.StdOutImpl - mapper-locations: classpath*:mapper/**/*.xml - type-aliases-package: com.tacit.admin.entity - -# Swagger Configuration -springdoc: - api-docs: - enabled: true - path: /v3/api-docs - swagger-ui: - enabled: true - path: /swagger-ui.html - -# Logging Configuration -logging: - level: - com.tacit.admin: debug diff --git a/tacit-app-api/pom.xml b/tacit-app-api/pom.xml index bca7f57..2d5265c 100644 --- a/tacit-app-api/pom.xml +++ b/tacit-app-api/pom.xml @@ -86,11 +86,6 @@ test - - - org.springframework.cloud - spring-cloud-starter-bootstrap - com.tacit common-redis diff --git a/tacit-app-api/src/main/resources/application-dev.yml b/tacit-app-api/src/main/resources/application-dev.yml index ac79bd8..a5632f7 100644 --- a/tacit-app-api/src/main/resources/application-dev.yml +++ b/tacit-app-api/src/main/resources/application-dev.yml @@ -1,3 +1,17 @@ -server: - port: 8083 +spring: + config: + import: "optional:nacos:${spring.application.name}.yaml" + cloud: + nacos: + discovery: + server-addr: 117.72.94.232:9091 + username: nacos + password: nacos + namespace: dev + config: + server-addr: 117.72.94.232:9091 + file-extension: yaml + username: nacos + password: nacos + namespace: dev diff --git a/tacit-app-api/src/main/resources/application-qa.yml b/tacit-app-api/src/main/resources/application-qa.yml index ac79bd8..ff87a27 100644 --- a/tacit-app-api/src/main/resources/application-qa.yml +++ b/tacit-app-api/src/main/resources/application-qa.yml @@ -1,3 +1,17 @@ -server: - port: 8083 +spring: + config: + import: "optional:nacos:${spring.application.name}.yaml" + cloud: + nacos: + discovery: + server-addr: 117.72.94.232:9091 + username: nacos + password: nacos + namespace: ${nacos.namespace} + config: + server-addr: 117.72.94.232:9091 + file-extension: yaml + username: nacos + password: nacos + namespace: ${nacos.namespace} diff --git a/tacit-app-api/src/main/resources/application.yml b/tacit-app-api/src/main/resources/application.yml index 3d7808a..6b98902 100644 --- a/tacit-app-api/src/main/resources/application.yml +++ b/tacit-app-api/src/main/resources/application.yml @@ -1,3 +1,5 @@ spring: + application: + name: tacit-app-api profiles: active: dev diff --git a/tacit-app-api/src/main/resources/bootstrap.yml b/tacit-app-api/src/main/resources/bootstrap.yml deleted file mode 100644 index 59221dd..0000000 --- a/tacit-app-api/src/main/resources/bootstrap.yml +++ /dev/null @@ -1,18 +0,0 @@ -spring: - application: - name: tacit-app-api - config: - import: "optional:nacos:${spring.application.name}.yaml" - cloud: - nacos: - discovery: - server-addr: ${nacos.server-addr:117.72.94.232:9091} - username: ${nacos.username:nacos} - password: ${nacos.password:nacos} - namespace: ${nacos.namespace:33140c53-3f57-4bd2-b9c8-f507581b6ca2} - config: - server-addr: ${nacos.server-addr:117.72.94.232:9091} - file-extension: yaml - username: ${nacos.username:nacos} - password: ${nacos.password:nacos} - namespace: ${nacos.namespace:33140c53-3f57-4bd2-b9c8-f507581b6ca2} diff --git a/tacit-gateway/pom.xml b/tacit-gateway/pom.xml index 99961ea..a4ea2ef 100644 --- a/tacit-gateway/pom.xml +++ b/tacit-gateway/pom.xml @@ -51,12 +51,6 @@ - - - org.springframework.cloud - spring-cloud-starter-bootstrap - - com.alibaba.cloud diff --git a/tacit-gateway/src/main/resources/application-dev.yml b/tacit-gateway/src/main/resources/application-dev.yml index 11e54c5..84e841b 100644 --- a/tacit-gateway/src/main/resources/application-dev.yml +++ b/tacit-gateway/src/main/resources/application-dev.yml @@ -1,2 +1,16 @@ -server: - port: 8081 +spring: + config: + import: "optional:nacos:${spring.application.name}.yaml" + cloud: + nacos: + discovery: + server-addr: 117.72.94.232:9091 + username: nacos + password: nacos + namespace: dev + config: + server-addr: 117.72.94.232:9091 + file-extension: yaml + username: nacos + password: nacos + namespace: dev \ No newline at end of file diff --git a/tacit-gateway/src/main/resources/application-qa.yml b/tacit-gateway/src/main/resources/application-qa.yml index 11e54c5..2ccfda6 100644 --- a/tacit-gateway/src/main/resources/application-qa.yml +++ b/tacit-gateway/src/main/resources/application-qa.yml @@ -1,2 +1,16 @@ -server: - port: 8081 +spring: + config: + import: "optional:nacos:${spring.application.name}.yaml" + cloud: + nacos: + discovery: + server-addr: 117.72.94.232:9091 + username: nacos + password: nacos + namespace: ${nacos.namespace} + config: + server-addr: 117.72.94.232:9091 + file-extension: yaml + username: nacos + password: nacos + namespace: ${nacos.namespace} diff --git a/tacit-gateway/src/main/resources/application.yml b/tacit-gateway/src/main/resources/application.yml index 3d7808a..a990477 100644 --- a/tacit-gateway/src/main/resources/application.yml +++ b/tacit-gateway/src/main/resources/application.yml @@ -1,3 +1,7 @@ spring: + application: + name: tacit-gateway + main: + web-application-type: reactive profiles: active: dev diff --git a/tacit-gateway/src/main/resources/bootstrap.yml b/tacit-gateway/src/main/resources/bootstrap.yml deleted file mode 100644 index ce0d220..0000000 --- a/tacit-gateway/src/main/resources/bootstrap.yml +++ /dev/null @@ -1,21 +0,0 @@ -spring: - application: - name: tacit-gateway - config: - import: "optional:nacos:${spring.application.name}.yaml" - main: - web-application-type: reactive - cloud: - nacos: - discovery: - server-addr: ${nacos.server-addr:117.72.94.232:9091} - username: ${nacos.username:nacos} - password: ${nacos.password:nacos} - namespace: ${nacos.namespace:33140c53-3f57-4bd2-b9c8-f507581b6ca2} - config: - server-addr: ${nacos.server-addr:117.72.94.232:9091} - file-extension: yaml - username: ${nacos.username:nacos} - password: ${nacos.password:nacos} - namespace: ${nacos.namespace:33140c53-3f57-4bd2-b9c8-f507581b6ca2} -