当前位置: > > > SpringBoot - MyBatis-Plus使用详解20(多数据源)

SpringBoot - MyBatis-Plus使用详解20(多数据源)

二十、多数据源

1,基本介绍

(1)dynamic-datasource-spring-boot-starter 是一个基于 springboot 的快速集成多数据源的启动器。其支持 Jdk 1.7+SpringBoot 1.4.x 1.5.x 2.0.x
注意:该插件可以不依赖 MyBatis-Plus,可以独立使用。

(2)它主要用于读写分离,一主多从的环境。(当然也可以纯粹当成多库使用)
一主多从的环境下数据库分工:
  • 主数据库建议只执行 INSERTUPDATEDELETE 操作。
  • 从数据库建议只执行 SELECT 操作。

2,功能特性

  • 数据源分组,适用于多种场景:纯粹多库、读写分离、一主多从、混合模式。
  • 内置敏感参数加密和启动初始化表结构 schema 数据库 database
  • 提供对 DruidMybatis-PlusP6syJndi 的快速集成。
  • 简化 Druid HikariCp 配置,提供全局参数配置。
  • 提供自定义数据源来源接口(默认使用 yml properties 配置)。
  • 提供项目启动后增减数据源方案。
  • 提供 Mybatis 环境下的 纯读写分离 方案。
  • 使用 spel 动态参数解析数据源,如从 sessionheader 或参数中获取数据源。(多租户架构神器)
  • 提供多层数据源嵌套切换。(ServiceA >>> ServiceB >>> ServiceC,每个 Service 都是不同的数据源)
  • 提供“不使用注解”而使用“正则”或 spel 来切换数据源方案(实验性功能)。
  • 基于 seata 的分布式事务支持。

3,安装配置

(1)首先编辑项目的 pom.xml 文件,引入 dynamic-datasource-spring-boot-starter 依赖:
<!-- 多数据源 -->
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>dynamic-datasource-spring-boot-starter</artifactId>
    <version>3.1.1</version>
</dependency>

(2)接着配置数据源,比如下面我们配置了一个主库、两个从库。
提示:
  • 配置文件中所有以下划线 _ 分割的数据源“首部”即为组的名称,相同组名称的数据源会放在一个组下。
  • 默认的数据源名称为 master ,我们可以通过 spring.datasource.dynamic.primary 修改。
spring:
datasource:
dynamic:
primary: master #设置默认的数据源或者数据源组,默认值即为master
strict: false #设置严格模式,默认false不启动. 启动后在未匹配到指定数据源时候回抛出异常,不启动会使用默认数据源.
datasource:
master:
url: jdbc:mysql://xx.xx.xx.xx:3306/hangge?serverTimezone=Asia/Shanghai
username: root
password: hangge1234
type: com.alibaba.druid.pool.DruidDataSource
slave_1:
url: jdbc:mysql://xx.xx.xx.xx:3307/hangge?serverTimezone=Asia/Shanghai
username: root
password: hangge1234
type: com.alibaba.druid.pool.DruidDataSource
slave_2:
url: jdbc:mysql://xx.xx.xx.xx:3308/hangge?serverTimezone=Asia/Shanghai
username: root
password: hangge1234
type: com.alibaba.druid.pool.DruidDataSource
  • 或者我们也可以配置多主多从:
spring:
datasource:
dynamic:
datasource:
master_1:
master_2:
slave_1:
slave_2:
slave_3:
  • 或者纯粹多库(记得设置 primary):
spring:
datasource:
dynamic:
datasource:
mysql:
oracle:
sqlserver:
postgresql:
h2:
  • 或者混合配置:
spring:
datasource:
dynamic:
datasource:
master:
slave_1:
slave_2:
oracle_1:
oracle_2:

(3)最后代码中使用 @DS 切换数据源。
  • @DS 可以注解在方法上和类上。如果同时存在,方法注解优先于类上注解。强烈建议注解在 service 实现或 mapper 接口方法上。
  • @DS("xxx") 指定使用 xxx 这个数据源,xxx 可以为组名也可以为具体某个库的名称。如果是组名则切换时采用负载均衡算法切换。如果指定的组名或者库不存在,则自动使用默认数据源(主库)
  • 如果没有 @DS,则使用默认数据源(主库)
  • 如果设置了 @DS 但没有指定某个组或者库,则根据 DynamicDataSourceStrategy 策略,选择一个从库。默认负载均衡策略。
@Service
@DS("slave")
public class UserServiceImpl implements UserService {

  @Autowired
  private JdbcTemplate jdbcTemplate;

  public List<Map<String, Object>> selectAll() {
    return  jdbcTemplate.queryForList("select * from user");
  }
  
  @Override
  @DS("slave_1")
  public List<Map<String, Object>> selectByCondition() {
    return  jdbcTemplate.queryForList("select * from user where age >10");
  }
}

  • mybatis 环境下也可注解在 mapper 接口层。比如下面我们在主数据库上执行 INSERTUPDATEDELETE 操作,而从数据库执行 SELECT 操作。
@DS("master")
public interface UserMapper {

  @Insert("INSERT INTO user (name,age) values (#{name},#{age})")
  boolean addUser(@Param("name") String name, @Param("age") Integer age);

  @Update("UPDATE user set name=#{name}, age=#{age} where id =#{id}")
  boolean updateUser(@Param("id") Integer id, @Param("name") String name, @Param("age") Integer age);

  @Delete("DELETE from user where id =#{id}")
  boolean deleteUser(@Param("id") Integer id);

  @Select("SELECT * FROM user")
  @DS
  List<User> selectAll();
}

附:样例演示

1,基本用法

(1)假设我们有 hangge hangge2 两个数据库,两个库中都有 user_info 这张表(不过两个库里数据不一样):
         

(2)在配置文件中一个设置为主库,一个设置为从库:
spring:
datasource:
dynamic:
primary: master #设置默认的数据源或者数据源组,默认值即为master
strict: false #设置严格模式,默认false不启动. 启动后在未匹配到指定数据源时候回抛出异常,不启动会使用默认数据源.
datasource:
master:
url: jdbc:mysql://localhost:3306/hangge?serverTimezone=Asia/Shanghai
username: root
password: hangge1234
type: com.alibaba.druid.pool.DruidDataSource
slave:
url: jdbc:mysql://localhost:3306/hangge2?serverTimezone=Asia/Shanghai
username: root
password: hangge1234
type: com.alibaba.druid.pool.DruidDataSource

(3)默认情况下,如果不做额外配置的话,都是操作主库:
@RestController
public class HelloController {

    @Autowired
    UserInfoService userInfoService;

    @GetMapping("/test")
    public List<UserInfo> test() {
        return userInfoService.list();
    }
}

(4)使用 @DS 切换数据源,这里我们将 UserInfoService 数据源切换成从库。再次进行查询,可以发现数据源确实发生变化。
@DS("slave")
public interface UserInfoService extends IService<UserInfo> {

}

2,负载均衡

(1)如果数据源指定的是一个分组,且该分组下有多个数据库,那么会自动进行负载均衡。比如我们在上面样例上稍作修改,配置了两个从库:
spring:
datasource:
dynamic:
primary: master #设置默认的数据源或者数据源组,默认值即为master
strict: false #设置严格模式,默认false不启动. 启动后在未匹配到指定数据源时候回抛出异常,不启动会使用默认数据源.
datasource:
master:
url: jdbc:mysql://localhost:3306/hangge?serverTimezone=Asia/Shanghai
username: root
password: hangge1234
type: com.alibaba.druid.pool.DruidDataSource
slave_1:
url: jdbc:mysql://localhost:3306/hangge2?serverTimezone=Asia/Shanghai
username: root
password: hangge1234
type: com.alibaba.druid.pool.DruidDataSource
slave_2:
url: jdbc:mysql://localhost:3306/hangge?serverTimezone=Asia/Shanghai
username: root
password: hangge1234
type: com.alibaba.druid.pool.DruidDataSource

(2)UserInfoService 同样通过 @DS 注解指定使用 slave 这个分组: 
@DS("slave")
public interface UserInfoService extends IService<UserInfo> {

}

(3)多次刷新浏览器,可以发现数据轮流从两个库中获取,说明负载均衡生效了。
评论0