引言
mybatis-plus 的多数据源组件 dynamic-datasource ,看介绍和网上的评价还不错,于是就想试试看。之前用多数据源用过若依项目里面的多数据源,比较麻烦。因此测试下集成非常简单好用。
介绍
dynamic-datasource-spring-boot-starter 是一个基于springboot的快速集成多数据源的启动器,看了一下确实很不错。值得推荐。
特性
- 支持 数据源分组 ,适用于多种场景 纯粹多库 读写分离 一主多从 混合模式。
- 支持数据库敏感配置信息 加密 ENC()。
- 支持每个数据库独立初始化表结构schema和数据库database。
- 支持无数据源启动,支持懒加载数据源(需要的时候再创建连接)。
- 支持 自定义注解 ,需继承DS(3.2.0+)。
- 提供并简化对Druid,HikariCp,BeeCp,Dbcp2的快速集成。
- 提供对Mybatis-Plus,Quartz,ShardingJdbc,P6sy,Jndi等组件的集成方案。
- 提供 自定义数据源来源 方案(如全从数据库加载)。
- 提供项目启动后 动态增加移除数据源 方案。
- 提供Mybatis环境下的 纯读写分离 方案。
- 提供使用 spel动态参数 解析数据源方案。内置spel,session,header,支持自定义。
- 支持 多层数据源嵌套切换 。(ServiceA >>> ServiceB >>> ServiceC)。
- 提供 基于seata的分布式事务方案。
- 提供 本地多数据源事务方案。 附:不能和原生spring事务混用。
这是文档上的介绍,我会进行分批次演示,本文介绍最基础的用法。
使用
1、引入依赖(当前最新版本3.5.1)
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>dynamic-datasource-spring-boot-starter</artifactId>
<version>3.5.1</version>
</dependency>
<!-- mybatis-plus -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.2</version>
</dependency>
2、数据库表
所有数据库只有 yixi_user 表,从数据上可以看出来是具体哪个库的数据,只是作为演示用,实际业务中主库和从库的数据是一样的。
CREATE TABLE `yx_user` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(20) DEFAULT NULL COMMENT '姓名',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4;
实体类代码
package com.azydbly.entity;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import java.io.Serializable;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
/**
* <p>
*
* </p>
*
* @author yixi
* @since 2022-08-19
*/
@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
@TableName("yx_user")
public class YxUser implements Serializable {
private static final long serialVersionUID = 1L;
@TableId(value = "id", type = IdType.AUTO)
private Integer id;
/**
* 姓名
*/
private String name;
}
3.1、一主多从配置
一主多从,master 配置的为主库(默认),slave 为从库组
server:
port: 8081
spring:
datasource:
dynamic:
# 设置默认的数据源或者数据源组,默认值即为master
primary: master
# 严格匹配数据源,默认false. true未匹配到指定数据源时抛异常,false使用默认数据源
strict: false
datasource:
master:
url: jdbc:mysql://localhost:3306/dynamic_master1?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&rewriteBatchedStatements=true
username: root
password: 123456
# 3.2.0开始支持SPI可省略此配置,其他库配置我进行了省略依旧可以使用
driver-class-name: com.mysql.cj.jdbc.Driver
slave_1:
url: jdbc:mysql://localhost:3306/dynamic_slave1?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&rewriteBatchedStatements=true
username: root
password: 123456
slave_2:
url: jdbc:mysql://localhost:3306/dynamic_slave2?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&rewriteBatchedStatements=true
username: root
password: 123456
slave_3:
url: jdbc:mysql://localhost:3306/dynamic_slave3?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&rewriteBatchedStatements=true
username: root
password: 123456
# 自定义负载均衡策略。slave组下有;多个个数据源,当用户使用 slave 切换数据源时会使用负载均衡算法。系统自带了两个负载均衡算法 LoadBalanceDynamicDataSourceStrategy 轮询,是默认的。 RandomDynamicDataSourceStrategy 随机的。
strategy: com.baomidou.dynamic.datasource.strategy.LoadBalanceDynamicDataSourceStrategy
默认使用 master 数据库,如何使用其他数据库,在类或者方法上增加注解 @DS("slave_1") 这样就可以使用 slave_1 数据库了,其他代码不用进行修改。
controller 代码
package com.azydbly.controller;
import com.azydbly.service.IYxUserService;
import com.baomidou.dynamic.datasource.annotation.DS;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import java.util.List;
/**
* <p>
* 前端控制器
* 一主多从
* @DS 可以注解在方法上或类上,同时存在就近原则 方法上注解 优先于 类上注解。
* </p>
*
* @author yixi
* @since 2022-08-19
*/
@RestController
@RequestMapping("/user")
public class YxUserController {
@Resource
private IYxUserService yxUserService;
/**
* 获取所有用户(主库)
*
* @return
*/
@GetMapping
public List getAllUser() {
return yxUserService.list();
}
/**
* 获取所有用户(从库1)
*
* @return
*/
@GetMapping("slave1")
@DS("slave_1")
public List getAllUserForSlaveOne() {
return yxUserService.list();
}
/**
* 获取所有用户(从库2)
*
* @return
*/
@GetMapping("slave2")
@DS("slave_2")
public List getAllUserForSlaveTwo() {
return yxUserService.list();
}
/**
* 获取所有用户(从库3)
*
* @return
*/
@GetMapping("slave3")
@DS("slave_3")
public List getAllUserForSlaveThree() {
return yxUserService.list();
}
/**
* 获取从库数据源
* 默认是从 slave 数据组中的数据库进行轮训访问,可修改配置文件进行随机访问。 默认为轮训访问
*
* @return
*/
@GetMapping("slave")
@DS("slave")
public List getAllUserForSlave() {
return yxUserService.list();
}
}
3.2、多主多从配置
多主多从,master 配置的为主库组,从库组
server:
port: 8081
spring:
datasource:
dynamic:
# 设置默认的数据源或者数据源组,默认值即为master
primary: master
# 严格匹配数据源,默认false. true未匹配到指定数据源时抛异常,false使用默认数据源
strict: false
datasource:
master_1:
url: jdbc:mysql://localhost:3306/dynamic_master1?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&rewriteBatchedStatements=true
username: root
password: 123456
# 3.2.0开始支持SPI可省略此配置,其他库配置我进行了省略依旧可以使用
driver-class-name: com.mysql.cj.jdbc.Driver
master_2:
url: jdbc:mysql://localhost:3306/dynamic_master2?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&rewriteBatchedStatements=true
username: root
password: 123456
slave_1:
url: jdbc:mysql://localhost:3306/dynamic_slave1?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&rewriteBatchedStatements=true
username: root
password: 123456
slave_2:
url: jdbc:mysql://localhost:3306/dynamic_slave2?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&rewriteBatchedStatements=true
username: root
password: 123456
slave_3:
url: jdbc:mysql://localhost:3306/dynamic_slave3?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&rewriteBatchedStatements=true
username: root
password: 123456
# 自定义负载均衡策略。slave组下有;多个个数据源,当用户使用 slave 切换数据源时会使用负载均衡算法。系统自带了两个负载均衡算法 LoadBalanceDynamicDataSourceStrategy 轮询,是默认的。 RandomDynamicDataSourceStrategy 随机的。
strategy: com.baomidou.dynamic.datasource.strategy.LoadBalanceDynamicDataSourceStrategy
controller 代码
package com.azydbly.controller;
import com.azydbly.service.IYxUserService;
import com.baomidou.dynamic.datasource.annotation.DS;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import java.util.List;
/**
* <p>
* 前端控制器
* 多主多从,主要演示多主,多从和一主多从是一样的
* @DS 可以注解在方法上或类上,同时存在就近原则 方法上注解 优先于 类上注解。
* </p>
*
* @author yixi
* @since 2022-08-19
*/
@RestController
@RequestMapping("/more/user")
public class MoreUserController {
@Resource
private IYxUserService yxUserService;
/**
* 获取所有用户(主库)
*
* @return
*/
@GetMapping
public List getAllUser() {
return yxUserService.list();
}
/**
* 获取从库数据源
* 默认是从 slave 数据组中的数据库进行轮训访问,可修改配置文件进行随机访问。 默认为轮训访问
*
* @return
*/
@GetMapping("master")
@DS("master")
public List getAllUserForSlave() {
return yxUserService.list();
}
}
官网还给出了其他的模式组合,这里不在进行赘述,有兴趣的小伙伴可以进行研究
# 多主多从 纯粹多库(记得设置primary) 混合配置
spring: spring: spring:
datasource: datasource: datasource:
dynamic: dynamic: dynamic:
datasource: datasource: datasource:
master_1: mysql: master:
master_2: oracle: slave_1:
slave_1: sqlserver: slave_2:
slave_2: postgresql: oracle_1:
slave_3: h2: oracle_2:
4、集成数据源
可以集成 Druid、HikariCP、BeeCP、DBCP2、Jndi,这里拿一主多从进行讲解集成 druid 数据源。
引入 druid 依赖
<!-- 阿里数据库连接池 druid -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.2.9</version>
</dependency>
配置文件(druid的参数之前的druid的用法一样)
server:
port: 8081
spring:
datasource:
druid:
statViewServlet:
enabled: true
# 设置白名单,不填则允许所有访问
allow:
# url-pattern: /druid/*
# 控制台管理用户名和密码
login-username: admin
login-password: 123456
dynamic:
# 以下是支持的全局默认值
druid:
# 初始连接数
initialSize: 5
# 最小连接池数量
minIdle: 10
# 最大连接池数量
maxActive: 20
# 配置获取连接等待超时的时间
maxWait: 60000
# 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
timeBetweenEvictionRunsMillis: 60000
# 配置一个连接在池中最小生存的时间,单位是毫秒
minEvictableIdleTimeMillis: 300000
# 配置一个连接在池中最大生存的时间,单位是毫秒
maxEvictableIdleTimeMillis: 900000
# 配置检测连接是否有效
validationQuery: SELECT 1 FROM DUAL
testWhileIdle: true
testOnBorrow: false
testOnReturn: false
webStatFilter:
enabled: true
filter:
stat:
enabled: true
# 慢SQL记录
log-slow-sql: true
slow-sql-millis: 1000
merge-sql: true
wall:
config:
multi-statement-allow: true
# 设置默认的数据源或者数据源组,默认值即为master
primary: master
# 严格匹配数据源,默认false. true未匹配到指定数据源时抛异常,false使用默认数据源
strict: false
datasource:
master:
url: jdbc:mysql://localhost:3306/dynamic_master1?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&rewriteBatchedStatements=true
username: root
password: 123456
# 3.2.0开始支持SPI可省略此配置,其他库配置我进行了省略依旧可以使用
driver-class-name: com.mysql.cj.jdbc.Driver
slave_1:
url: jdbc:mysql://localhost:3306/dynamic_slave1?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&rewriteBatchedStatements=true
username: root
password: 123456
slave_2:
url: jdbc:mysql://localhost:3306/dynamic_slave2?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&rewriteBatchedStatements=true
username: root
password: 123456
slave_3:
url: jdbc:mysql://localhost:3306/dynamic_slave3?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&rewriteBatchedStatements=true
username: root
password: 123456
# 自定义负载均衡策略。slave组下有;多个个数据源,当用户使用 slave 切换数据源时会使用负载均衡算法。系统自带了两个负载均衡算法 LoadBalanceDynamicDataSourceStrategy 轮询,是默认的。 RandomDynamicDataSourceStrategy 随机的。
strategy: com.baomidou.dynamic.datasource.strategy.LoadBalanceDynamicDataSourceStrategy
5、自定义注解
在数据源确定的情况下,可以进行自定义注解
package com.azydbly.datasource;
import com.baomidou.dynamic.datasource.annotation.DS;
import java.lang.annotation.*;
/**
* @ClassName: SlaveOne
* @Description: 数据源-从库1
* @Author: yi•xi
* @CreateDate: 2022/8/19 21:35
*/
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@DS("slave_1")
public @interface SlaveOne {
}
用法,和 @DB() 的用法一样, 在需要的方法或者类上加 @SlaveOne 即可
controller 代码
package com.azydbly.controller;
import com.azydbly.datasource.SlaveOne;
import com.azydbly.datasource.SlaveThree;
import com.azydbly.datasource.SlaveTwo;
import com.azydbly.service.IYxUserService;
import com.baomidou.dynamic.datasource.annotation.DS;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import java.util.List;
/**
* <p>
* 前端控制器
* 自定义注解
* </p>
*
* @author yixi
* @since 2022-08-19
*/
@RestController
@RequestMapping("/custom/user")
public class CustomUserController {
@Resource
private IYxUserService yxUserService;
/**
* 获取所有用户(从库1)
*
* @return
*/
@GetMapping("slave1")
@SlaveOne
public List getAllUserForSlaveOne() {
return yxUserService.list();
}
/**
* 获取所有用户(从库2)
*
* @return
*/
@GetMapping("slave2")
@SlaveTwo
public List getAllUserForSlaveTwo() {
return yxUserService.list();
}
/**
* 获取所有用户(从库3)
*
* @return
*/
@GetMapping("slave3")
@SlaveThree
public List getAllUserForSlaveThree() {
return yxUserService.list();
}
}
总结
其实官网上还有很多用法,集成也非常简单。感兴趣的小伙伴可以购买官网的文档进行学习。在集成中遇到问题也可以来进行探讨。
接口文档地址:www.apifox.cn/apidoc/shar…
懿曦:早晨的太阳