SpringBoot整合MybatisPlus多数据源

前言

随着业务的不断扩展和复杂度的增加,我们在开发过程中往往需要访问多个数据库。比如:我们可能需要同时访问主数据库和从数据库,或者访问多个独立的数据库来处理不同的业务逻辑。这时候,我们就需要使用多数据源来实现对多个数据库的操作。

SpringBoot整合Mybatis-plus

在之前的文章SpringBoot整合MyBatis-Plus已经详细介绍过,本文就不在多做介绍了。

进行整合

引入pom依赖


    com.alibaba
    druid-spring-boot-starter
    1.2.19

    com.baomidou
    mybatis-plus-generator
    3.5.3.2

    com.baomidou
    dynamic-datasource-spring-boot-starter
    4.1.3

yml文件配置

spring:
  application:
    name: springboot-demo

  #配置数据库信息
  datasource:
    dynamic:
      primary: master
      strict: false
      datasource:
        master:
          url: jdbc:mysql://ip:3306/test?useUnicode=true&characterEncoding=utf8&allowMultiQueries=true&useSSL=false&useAffectedRows=true&serverTimezone=Asia/Shanghai
          driver-class-name: com.mysql.cj.jdbc.Driver
          username: 账号
          password: 密码
        slave1:
          url: jdbc:mysql://ip:3306/test1?useUnicode=true&characterEncoding=utf8&allowMultiQueries=true&useSSL=false&useAffectedRows=true&serverTimezone=Asia/Shanghai
          driver-class-name: com.mysql.cj.jdbc.Driver
          username: 账号
          password: 密码
    type: com.alibaba.druid.pool.DruidDataSource

#配置mybatis-plus信息
mybatis-plus:
  configuration:
    #日志
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
    #驼峰形式显示
    map-underscore-to-camel-case: true
  mapper-locations: classpath:mybatis-mapper/*.xml
  global-config:
    db-config:
      #全局逻辑删除的实体字段名
      logic-delete-field: isDeleted
      #逻辑已删除值(默认为1)
      logic-delete-value: 1
      #逻辑未删除值(默认为0)
      logic-not-delete-value: 0

创建两个数据库及创建表

主数据库test

image.png user表结构

image.png

从数据库test1

image.png class_info表结构

image.png

创建各自的实体类

package com.example.springbootdemo.entity;

import com.baomidou.mybatisplus.annotation.*;
import com.example.springbootdemo.enums.GenderEnum;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.experimental.Accessors;

import java.io.Serializable;
import java.time.LocalDateTime;

/**
 * 
<p>
 *  用户实体类
 * </p>
 *
 * @author yurenwei
 * @since 2023/9/7
 */
@ApiModel(value = "用户参数", description = "用户参数")
@Data
@Accessors(chain = true)
@TableName("user")
public class User implements Serializable {

    private static final long serialVersionUID = 1L;

    /**
     * 主键id
     */
    @ApiModelProperty(value = "主键id")
    @TableId(value = "id", type = IdType.ASSIGN_ID)
    private Long id;

    /**
     * 姓名
     */
    @ApiModelProperty(value = "姓名")
    private String userName;

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

    /**
     * 性别
     */
    @ApiModelProperty(value = "性别")
    private GenderEnum gender;

    /**
     * 地址
     */
    @ApiModelProperty(value = "地址")
    private String address;

    /**
     * 状态(0、禁用1、启用)
     */
    @ApiModelProperty(value = "状态(0、禁用1、启用)")
    private Boolean status;

    /**
     * 注册时间
     */
    @ApiModelProperty(value = "注册时间")
    @JsonDeserialize(using = LocalDateTimeDeserializer.class)
    @JsonSerialize(using = LocalDateTimeSerializer.class)
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    private LocalDateTime registerTime;

    /**
     * 创建人
     */
    @ApiModelProperty(value = "创建人")
    private Long createBy;

    /**
     * 创建时间
     */
    @ApiModelProperty(value = "创建时间")
    @JsonDeserialize(using = LocalDateTimeDeserializer.class)
    @JsonSerialize(using = LocalDateTimeSerializer.class)
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    @TableField(fill = FieldFill.INSERT)
    private LocalDateTime createTime;

    /**
     * 修改人
     */
    @ApiModelProperty(value = "修改人")
    private Long updateBy;

    /**
     * 修改时间
     */
    @ApiModelProperty(value = "修改时间")
    @JsonDeserialize(using = LocalDateTimeDeserializer.class)
    @JsonSerialize(using = LocalDateTimeSerializer.class)
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private LocalDateTime updateTime;

    /**
     * 是否删除(0、否1、是)
     */
    @ApiModelProperty(value = "是否删除(0、否1、是)")
    private Boolean isDeleted;
}
package com.example.springbootdemo.entity;

import com.baomidou.mybatisplus.annotation.*;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.experimental.Accessors;

import java.io.Serializable;
import java.time.LocalDateTime;

/**
 * 
<p>
 *  班级实体类
 * </p>
 *
 * @author yurenwei
 * @since 2023/9/25
 */
@ApiModel(value = "班级参数", description = "班级参数")
@Data
@Accessors(chain = true)
@TableName("class_info")
public class ClassInfo implements Serializable {
    private static final long serialVersionUID = 1L;

    /**
     * 主键id
     */
    @ApiModelProperty(value = "主键id")
    @TableId(value = "id", type = IdType.ASSIGN_ID)
    private Long id;

    /**
     * 班级名称
     */
    @ApiModelProperty(value = "班级名称")
    private String className;

    /**
     * 创建人
     */
    @ApiModelProperty(value = "创建人")
    private Long createBy;

    /**
     * 创建时间
     */
    @ApiModelProperty(value = "创建时间")
    @JsonDeserialize(using = LocalDateTimeDeserializer.class)
    @JsonSerialize(using = LocalDateTimeSerializer.class)
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    @TableField(fill = FieldFill.INSERT)
    private LocalDateTime createTime;

    /**
     * 修改人
     */
    @ApiModelProperty(value = "修改人")
    private Long updateBy;

    /**
     * 修改时间
     */
    @ApiModelProperty(value = "修改时间")
    @JsonDeserialize(using = LocalDateTimeDeserializer.class)
    @JsonSerialize(using = LocalDateTimeSerializer.class)
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private LocalDateTime updateTime;

    /**
     * 是否删除(0、否1、是)
     */
    @ApiModelProperty(value = "是否删除(0、否1、是)")
    private Boolean isDeleted;

}

创建各自mapper

package com.example.springbootdemo.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.example.springbootdemo.entity.User;
import org.springframework.stereotype.Repository;

/**
 * 
<p>
 *  用户mapper
 * </p>
 *
 * @author yurenwei
 * @since 2023/9/7
 */
@Repository
public interface UserMapper extends BaseMapper {
}
package com.example.springbootdemo.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.example.springbootdemo.entity.ClassInfo;
import org.springframework.stereotype.Repository;

/**
 * 
<p>
 *  班级mapper
 * </p>
 *
 * @author yurenwei
 * @since 2023/9/25
 */
@Repository
public interface ClassInfoMapper extends BaseMapper {
}

创建各自接口

package com.example.springbootdemo.mybatisplus;

import com.baomidou.mybatisplus.extension.service.IService;
import com.example.springbootdemo.entity.User;

/**
 * 
<p>
 *  用户接口
 * </p>
 *
 * @author yurenwei
 * @since 2023/9/7
 */
public interface IUserService extends IService {
}
package com.example.springbootdemo.mybatisplus;

import com.baomidou.mybatisplus.extension.service.IService;
import com.example.springbootdemo.entity.ClassInfo;

/**
 * 
<p>
 *  班级接口机
 * </p>
 *
 * @author yurenwei
 * @since 2023/9/25
 */
public interface IClassInfoService extends IService {
}

创建各自接口实现类

package com.example.springbootdemo.mybatisplus.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.springbootdemo.entity.User;
import com.example.springbootdemo.mapper.UserMapper;
import com.example.springbootdemo.mybatisplus.IUserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

/**
 * 
<p>
 *  用户接口实现类
 * </p>
 *
 * @author yurenwei
 * @since 2023/9/7
 */
@Slf4j
@Service
public class UserServiceImpl extends ServiceImpl implements IUserService {
}
package com.example.springbootdemo.mybatisplus.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.springbootdemo.entity.ClassInfo;
import com.example.springbootdemo.mapper.ClassInfoMapper;
import com.example.springbootdemo.mybatisplus.IClassInfoService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

/**
 * 
<p>
 *  班级接口实现类
 * </p>
 *
 * @author yurenwei
 * @since 2023/9/25
 */
@Slf4j
@Service
public class ClassInfoServiceImpl extends ServiceImpl implements IClassInfoService {
}

怎么区分主从数据库呢

user表是在我们的主数据库master里,class_info表是在我们从数据库slave里,那么我们在开发的时候如何区分他们呢?

这就需要我们使用一个注解@DS 来进行区分,我们在各自的接口实现类上添加注解

image.png

image.png

编写测试类进行测试

package com.example.springbootdemo;

import cn.hutool.core.util.IdUtil;
import com.example.springbootdemo.entity.ClassInfo;
import com.example.springbootdemo.entity.User;
import com.example.springbootdemo.enums.GenderEnum;
import com.example.springbootdemo.mybatisplus.IClassInfoService;
import com.example.springbootdemo.mybatisplus.IUserService;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.time.LocalDateTime;

@Slf4j
@SpringBootTest
public class SpringbootDemoApplicationTests {

    @Autowired
    private IUserService iUserService;

    @Autowired
    private IClassInfoService iClassInfoService;

    /**
     * 测试动态数据源
     */
    @Test
    public void testDynamicDatasource(){
        User user = new User()
                .setId(IdUtil.getSnowflakeNextId())
                .setUserName("测试")
                .setPhone("13000000000")
                .setGender(GenderEnum.MALE)
                .setAddress("山东")
                .setStatus(true)
                .setRegisterTime(LocalDateTime.now());
        iUserService.save(user);

        ClassInfo c = new ClassInfo()
                .setId(IdUtil.getSnowflakeNextId())
                .setClassName("三年一班");
        iClassInfoService.save(c);
        log.info("---over---");
    }

}

执行测试类

image.png

查看数据库数据

image.png

image.png 两个数据库的两张表的数据都已经被成功插入。

至此,SpringBoot整合Mybatis-Plus多数据源结束了。