多数据源(动态数据源)的需求:
- 不同的业务分多个数据库场景,比方一个程序负责n个省份的db操作
- 一主多从的读写分离的场景(一主多从可以使用MyBatis插件的方式实现)
dynamic-datasource
dynamic-datasource 是一个开源的 Spring Boot 多数据源启动器,提供了丰富的功能,包罗数据源分组、敏感信息加密、独立初始化表结构等。
以下步骤在SpringBoot项目基础上实现:
1. 引入依靠:
- <dependency>
- <groupId>com.baomidou</groupId>
- <artifactId>dynamic-datasource-spring-boot-starter</artifactId>
- <version>3.1.0</version>
- </dependency>
复制代码 2. 通过yml配置数据源:
默认数据源名为 master,可通过 spring.datasource.dynamic.primary 修改。
- spring:
- datasource:
- dynamic:
- primary: master #设置默认的数据源或者数据源组,默认值即为master
- strict: false #设置严格模式,默认false不启动. 启动后在未匹配到指定数据源时候回抛出异常,不启动会使用默认数据源.
- datasource:
- master:
- url: jdbc:mysql://xxxxa:3449/db1?rewriteBatchedStatements=true&useUnicode=true&characterEncoding=utf8&useSSL=false&&serverTimezone=Asia/Shanghai&&zeroDateTimeBehavior=convertToNull
- username: 用户名
- password: 密码
- driver-class-name: com.mysql.cj.jdbc.Driver
- slave_1:
- url: jdbc:mysql://xxxxb:3449/db2?rewriteBatchedStatements=true&useUnicode=true&characterEncoding=utf8&useSSL=false&&serverTimezone=Asia/Shanghai&&zeroDateTimeBehavior=convertToNull
- username: 用户名
- password: 密码
- driver-class-name: com.mysql.cj.jdbc.Driver
-
复制代码 3. 使用 @DS 切换数据源:
使用 @DS 注解来指定必要切换到的数据源,DS内部填写的值就是yml内里配置的key。
service层内里在想要切换数据源的方法上加上@DS注解就行了,也可以加在整个service层上,方法上的注解优先于类上注解。
注解结果没有@DS默认数据源@DS(“dsName”)dsName可以为组名也可以为具体某个库的名称;数据源名称即yml内里配置的key 本案例读取master数据库中的数据,写入到slave_1数据库的新表中。
实体类上添加注解@DS("slave_1")指明当前类所使用的数据库。
- @Data
- @Accessors(chain = true)
- @TableName("T_STUDENT")
- @ApiModel(value="T_STUDENT", description="学生表")
- @DS("slave_1")
- public class StudentVerified {
- @ApiModelProperty(value = "主键")
- @TableField("id")
- private Long id;
- @ApiModelProperty(value = "姓名")
- @TableField("username")
- private String username;
- @ApiModelProperty(value = "身份证号")
- @TableField("idCardNumber")
- private String idCardNumber;
- }
复制代码 假如要使用mybatisplus方法,需直接在Service类上直接添加注解
- @Service
- @RequiredArgsConstructor(onConstructor = @__(@Autowired))
- @DS("slave_1")
- public class StudentVerifiedServiceImpl extends ServiceImpl<StudentVerifiedMapper, StudentVerified> {
- }
复制代码- public interface StudentVerifiedMapper extends BaseMapper<StudentVerified> {
- }
复制代码 使用master主数据源(不需做任何操作,和之前单数据库一样)
启动项目时可以看到相关日志输出
4. 在测试方法中实现逻辑
- @SpringBootTest
- public class Multidata {
- @Autowired
- private IBusCertificationService certificationService;
- @Autowired
- private StudentVerifiedServiceImpl studentVerifiedService;
- /**
- * 将master的实名认证数据导入到slave的Student表中
- */
- @Test
- void mult(){
- List<BusCertification> userCertification = certificationService.list();
- List<StudentVerified> studentVerifiedList = new ArrayList<>();
- for (BusCertification busCertification : userCertification) {
- StudentVerified studentVerified = new StudentVerified();
- studentVerified.setId(busCertification.getId());
- studentVerified.setUsername(busCertification.getUsername());
- studentVerified.setIdCardNumber(busCertification.getIdCardNumber());
- studentVerifiedList.add(studentVerified);
- }
- //此处调用方法时会根据注解切换到slave数据库中
- studentVerifiedService.saveBatch(studentVerifiedList);
- }
-
- }
复制代码 多数据源项目使用@DS切换数据库在事务中失效问题
假如在同一个方法内分别操作了主从库,而且方法上有事务注解,很有可能会导致从库查询失败。因为加入@Transitional注解后,数据源切换会失效,只会操作主库。
此时需将方法上注解修改为
- @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW)
- public void applyCheck(ApplyCheckPO po) {
- //······
- //调用从库方法
- }
复制代码 同时,最好将从库相关操作放置从库serviceImpl的方法中,再由外层调用该方法并try…catch环绕,同时从库该方法上也加上注解
- @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW)
复制代码 免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |