# 多数据源组件

# 概述

随着业务量的扩大,我们通常会进行数据库拆分或是引入其他数据库,从而我们需要配置多个数据源,此组件是一个能够快速集成多数据源功能的组件。

# 配置

# 引入依赖

<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>dynamic-datasource-spring-boot-starter</artifactId>
</dependency>

# 配置项说明

spring:
  datasource:
    dynamic:
      primary: master #设置默认的数据源或者数据源组,默认值即为master
      strict: false #严格匹配数据源,默认false. true未匹配到指定数据源时抛异常,false使用默认数据源
      datasource:
        master:
          url: jdbc:mysql://xx.xx.xx.xx:3306/dynamic
          username: root
          password: 123456
          driver-class-name: com.mysql.jdbc.Driver 
        slave1:
          url: jdbc:mysql://xx.xx.xx.xx:3307/dynamic
          username: root
          password: 123456
          driver-class-name: com.mysql.jdbc.Driver
        slave2:
          url:jdbc:oracle:thin:@114.242.xxx.xxxx:8521/XE
          username: HOS_APP_2_DEV
          password: xxxxxx
          driver-class-name: oracle.jdbc.driver.OracleDriver

该组件可以支持不同的数据库,如mysql、oracle、人大金仓等,使用时直接配置相应的数据库地址(url)、驱动名(driver-class-name)即可。

# 使用 @DS 切换数据源

@DS 可以注解在方法上或类上,同时存在就近原则 方法上注解 优先于 类上注解。

注解 结果
没有@DS 默认数据源
@DS("dsName") dsName可以为组名也可以为具体某个库的名称
@Service
public class OrganizationServiceImpl implements OrganizationService {


    @Autowired
    OrganizationMapper organizationMapper;


    @DS(DataSourceConstant.SLAVE1)
    @Override
    public List<Organization> selectALL() {
        return organizationMapper.selectList();
    }
}

# 约定

  • 多数据源组件只做 切换数据源 这件核心的事情,并不限制你的具体操作,切换了数据源可以做任何CRUD。
  • 配置文件所有以下划线 _ 分割的数据源 首部 即为组的名称,相同组名称的数据源会放在一个组下。
  • 切换数据源可以是组名,也可以是具体数据源名称。组名则切换时采用负载均衡算法切换。
  • 默认的数据源名称为 master ,你可以通过 spring.datasource.dynamic.primary 修改。
  • 方法上的注解优先于类上注解。
  • DS支持继承抽象类上的DS,暂不支持继承接口上的DS。

# 示例

# 引入依赖

在需要多数据源的工程中引入下面的依赖

<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>dynamic-datasource-spring-boot-starter</artifactId>
</dependency>

# 修改配置文件中数据源配置

spring:
  datasource:
    dynamic:
      primary: master #设置默认的数据源或者数据源组,默认值即为master
      strict: false #严格匹配数据源,默认false. true未匹配到指定数据源时抛异常,false使用默认数据源
      datasource:
        master:
          url: jdbc:mysql://xx.xx.xx.xx:3306/dynamic
          username: root
          password: 123456
          driver-class-name: com.mysql.jdbc.Driver
        slave1:
          url: jdbc:mysql://xx.xx.xx.xx:3307/dynamic
          username: root
          password: 123456
          driver-class-name: com.mysql.jdbc.Driver

# 在测试库中执行以下SQL

在master库及slave库中分别新建表

CREATE TABLE `staff`  (
  `id` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '主键',
  `name` varchar(60) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '姓名',
  `gender` varchar(2) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '性别',
  `age` int(2) NULL DEFAULT NULL COMMENT '年龄',
  `email` varchar(60) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '邮箱',
  `phone` varchar(60) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '手机号',
  `org_id` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '部门id',
  `description` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '描述',
  `create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `update_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间',
  `tenant_id` bigint(20) NULL DEFAULT NULL COMMENT '租户id',
  `is_deleted` int(1) NULL DEFAULT NULL,
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '员工信息表' ROW_FORMAT = Dynamic;

在master中执行以下SQL

INSERT INTO staff
(id, name, gender, age, email, phone, org_id, description, create_time, update_time, tenant_id, is_deleted)
VALUES('1', '张工', '男', 25, 'zhangsan@mediway.com', '1321111111111', NULL, NULL, '2023-05-18 18:23:51', '2023-05-19 08:56:39', NULL, NULL);

在salve中执行以下SQL

INSERT INTOstaff
(id, name, gender, age, email, phone, org_id, description, create_time, update_time, tenant_id, is_deleted)
VALUES('2', '李工', '女', 22, 'ligong@mediway.com', '132222222222', NULL, NULL, '2023-05-18 18:25:56', '2023-05-19 08:56:21', NULL, NULL);

# 编写测试代码

# DataSourceConstant.java

数据源常量类

package com.mediway.oa.user.constant;

public class DataSourceConstant {

    public static final String MASTER = "master";
    public static final String SLAVE1 = "slave1";
    
}

# Staff.java

staff表对应的实体类

package com.mediway.oa.user.model.entity;

import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import com.mediway.hos.database.model.BaseEntity;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;

/**
 * <p>
 * 员工信息表
 * </p>
 *
 * @author 代码生成器
 * @since 2022-02-19
 */
@Data
@EqualsAndHashCode(callSuper = true)
@Accessors(chain = true)
@ApiModel(value="Staff对象", description="员工信息表")
@TableName(value = "staff", autoResultMap = true)
public class Staff extends BaseEntity {

    private static final long serialVersionUID = 1L;

    @ApiModelProperty(value = "姓名")
    private String name;

    @ApiModelProperty(value = "性别")
    @TableField("gender")
    private String gender;

    @ApiModelProperty(value = "年龄")
    @TableField("age")
    private Integer age;

    @ApiModelProperty(value = "邮箱")
    @TableField("email")
    private String email;

    @ApiModelProperty(value = "手机号")
    private String phone;

    @ApiModelProperty(value = "部门id")
    @TableField("org_id")
    private String orgId;

    @ApiModelProperty(value = "描述")
    @TableField("description")
    private String description;

    @ApiModelProperty(value = "租户id")
    @TableField("tenant_id")
    private String tenantId;

    @TableField("is_deleted")
    private Integer isDeleted;
    
}

# StaffMapper.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.mediway.oa.user.mapper.StaffMapper">

    <select id="selectListStaff"  resultType="com.mediway.oa.user.model.entity.Staff">
        select
            id,name,age,gender,email,phone
        from staff
    </select>

</mapper>

# StaffMapper.java

package com.mediway.oa.user.mapper;


import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.mediway.oa.user.model.entity.Staff;

import java.util.List;

public interface StaffMapper extends BaseMapper<Staff> {

    List<Staff> selectListStaff();

}

# StaffService.java

package com.mediway.oa.user.service;


import com.mediway.oa.user.model.entity.Staff;
import org.springframework.stereotype.Service;

import java.util.List;

/**
 * @Author 开发平台
 * @Date Mon Sep 27 11:34:47 CST 2021
 * @description
 */
@Service
public interface StaffService{
    
    List<Staff> selectALL1();

    List<Staff> selectALL2();
    
}

# StaffServiceImpl.java

在需要使用分库的service方法或类上加@DS注解

package com.mediway.oa.user.service.impl;


import com.baomidou.dynamic.datasource.annotation.DS;
import com.mediway.oa.user.constant.DataSourceConstant;
import com.mediway.oa.user.mapper.StaffMapper;
import com.mediway.oa.user.model.entity.Staff;
import com.mediway.oa.user.service.StaffService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

/**
 * @Author 开发平台
 * @Date Mon Sep 27 11:34:47 CST 2021
 * @description
 */
@Service
public class StaffServiceImpl implements StaffService {


    @Autowired
    StaffMapper staffMapper;

    @Override
    public List<Staff> selectALL1() {
        return staffMapper.selectListStaff();
    }

    @DS(DataSourceConstant.SLAVE1)
    @Override
    public List<Staff> selectALL2() {
        return staffMapper.selectListStaff();
    }
}

# StaffController

package com.mediway.oa.user.controller;

import com.mediway.hos.base.model.BaseResponse;
import com.mediway.oa.user.model.entity.Staff;
import com.mediway.oa.user.service.StaffService;
import io.swagger.annotations.Api;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

@Api(tags = "员工信息")
@RestController
@RequestMapping("/user/staff")
public class StaffController  {

    @Autowired
    private StaffService staffService;



    @PostMapping("/selectALL1")
    public BaseResponse<List<Staff>> selectALL1() {
        return BaseResponse.success(staffService.selectALL1());
    }

    @PostMapping("/selectALL2")
    public BaseResponse<List<Staff>> selectALL2() {
        return BaseResponse.success(staffService.selectALL2());
    }
    
}

# 演示效果

访问http://localhost:8080/api//user/staff/selectALL1

img_1.png

访问http://localhost:8080/api//user/staff/selectALL2

img_2.png