文章目录
前言
在日常大型项目中经常会遇到分库分表的数据库设计,咱们普通的SpringBoot 单体项目通过默认配置及注解可以很容易实现对单个数据库的操作管理,但遇到需要多个数据库操作可能会比较麻烦,因此咱们今天主要介绍如何使用MyBatis-Plus提供的一个多数据源动态加载组件简单轻松实现在单个项目中实现对多个数据库的操作管理。
关键词:SpringBoot 、MyBatis、MyBatis-Plus、多数据源
一、Mybatis-Plus是什么?
Mybatis-Plus是一个Mybatis(opens new window)的增强工具,在Mybatis的基础上只做增强不做改变,为简化开发。
二、多数据源是什么?
多数据源是指在分布式环境或集群环境下,为不同的数据库(如MySQL、Oracle、SQLServer等)配置数据源,以便在项目中能够随意切换以获取数据。这种配置方式允许应用程序根据需要连接到不同的数据库,以实现特定的业务需求,如数据隔离、水平扩展、读写分离等。
三、使用步骤
1. 新建一个SpringBoot项目
可以通过Ide工具向导建立,这里不详细描述了。
2. 引入必要的MyBatis架包
在项目的pom.xml加入如何内容
<!-- mysql -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.18</version>
</dependency>
<!-- 连接池 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.24</version>
</dependency>
<!-- mybatis plus -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>${mybatisplus-spring-boot-starter.version}</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus</artifactId>
<version>>3.4.2</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>3.4.1</version>
</dependency>
<dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity-engine-core</artifactId>
<version>2.3</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>dynamic-datasource-spring-boot-starter</artifactId>
<version>3.5.0</version>
</dependency>
3. 新建两个数据库及两张表
3.3.1 新建数据库:DB_A,并创建一张数据表alarm_kind,以及一些测试数据。
CREATE DATABASE IF NOT EXISTS `DB_A` /*!40100 DEFAULT CHARACTER SET utf8mb4 */;
USE `DB_A`;
DROP TABLE IF EXISTS `alarm_kind`;
CREATE TABLE IF NOT EXISTS `alarm_kind` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
`type_no` varchar(255) DEFAULT NULL COMMENT '类型编号',
`type_name` varchar(255) DEFAULT NULL COMMENT '类型名称',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=23 DEFAULT CHARSET=utf8mb4 COMMENT='报警类型字典表';
DELETE FROM `alarm_kind`;
INSERT INTO `alarm_kind` (`id`, `type_no`, `type_name`) VALUES
(1, 'Powon', '市电'),
(2, 'Baton', 'UPS电源'),
(3, 'Move', '位移'),
(4, 'Alarm', '震动'),
(5, 'Cut', '切割检测'),
(6, 'Smoke', '烟雾'),
(7, 'LBJ', '声光'),
(8, 'HW', '红外'),
(9, 'Box4_NoPutTimeOut', '四号柜款箱未放入');
3.3.2 同样再建一个数据库DB_B,并创建一张数据表test,以及一些测试数据。
CREATE DATABASE IF NOT EXISTS `DB_B` /*!40100 DEFAULT CHARACTER SET utf8mb4 */;
USE `DB_B`;
DROP TABLE IF EXISTS `test`;
CREATE TABLE IF NOT EXISTS `alarm_kind` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
`type_no` varchar(255) DEFAULT NULL COMMENT '类型编号',
`type_name` varchar(255) DEFAULT NULL COMMENT '类型名称',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=23 DEFAULT CHARSET=utf8mb4 COMMENT='报警类型字典表';
DELETE FROM `test`;
INSERT INTO `test` (`id`, `type_no`, `type_name`) VALUES
(1, 'Powon', '测试1'),
(2, 'Baton', '测试2'),
(3, 'Move', '测试3');
4. 修改配置文件application.yml
server:
port: 8085 #服务端口配置
spring:
application:
name: ms-base
datasource:
dynamic:
primary: baseA #默认加载的数据库是DB_A
strict: false
datasource:
baseA:
driver-class-name: com.mysql.cj.jdbc.Driver #数据源配置
url: jdbc:mysql://127.0.0.1:13306/DB_A?serverTimezone=GMT%2B8&useSSL=false
username: root
password: data@123456!
type: com.alibaba.druid.pool.DruidDataSource #连接池配置
max-idle: 10 #No operations allowed after connection closed错误原因及解决
max-wait: 10000
min-idle: 5
initial-size: 5
validation-query: SELECT 1
test-on-borrow: false
test-while-idle: true
time-between-eviction-runs-millis: 18800
baseB:
driver-class-name: com.mysql.cj.jdbc.Driver #数据源配置
url: jdbc:mysql:///127.0.0.1:13306/DB_B?serverTimezone=GMT%2B8&useSSL=false
username: root
password: data@123456!
type: com.alibaba.druid.pool.DruidDataSource #连接池配置
max-idle: 10 #No operations allowed after connection closed错误原因及解决
max-wait: 10000
min-idle: 5
initial-size: 5
validation-query: SELECT 1
test-on-borrow: false
test-while-idle: true
time-between-eviction-runs-millis: 18800
5. 编码
5.1 entity 实体类
AlarmKind.java
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import java.time.LocalDateTime;
import java.io.Serializable;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* <p>
* 报警类型字典表
* </p>
*
* @since 2022-05-24
*/
@Data
@EqualsAndHashCode(callSuper = false)
public class AlarmKind implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 主键ID
*/
@TableId(value = "id", type = IdType.AUTO)
private Long id;
/**
* 类型编号
*/
private String typeNo;
/**
* 类型名称
*/
private String typeName;
}
Test.java
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import java.time.LocalDateTime;
import java.io.Serializable;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* <p>
* 测试表
* </p>
*
*/
@Data
@EqualsAndHashCode(callSuper = false)
public class Test implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 主键ID
*/
@TableId(value = "id", type = IdType.AUTO)
private Long id;
/**
* 类型编号
*/
private String typeNo;
/**
* 类型名称
*/
private String typeName;
}
5.2 mapper接口
AlarmKIndMapper.java
import com.xxxx.rest.entity.AlarmKind;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
/**
* <p>
* 报警类型字典表 Mapper 接口
* </p>
*
*/
public interface AlarmKindMapper extends BaseMapper<AlarmKind> {
List<AlarmKind> getAll();
}
TestMapper.java
import com.xxxx.rest.entity.Test;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
/**
* <p>
* 测试表 Mapper 接口
* </p>
*
*/
public interface TestMapper extends BaseMapper<Test> {
List<Test> getAll();
}
5.3 service服务接口
IAlarmKIndService.java
import com.xxx.rest.entity.AlarmKind;
import com.baomidou.mybatisplus.extension.service.IService;
import com.xianban.rest.model.msbase.vo.platform.BaseLineVO;
import java.util.List;
/**
* <p>
* 报警类型表 服务类
* </p>
*
*/
public interface IAlarmKindService extends IService<AlarmKind> {
List<AlarmKind> getAll();
}
ITestService.java
import com.xxx.rest.entity.Test;
import com.baomidou.mybatisplus.extension.service.IService;
import com.xianban.rest.model.msbase.vo.platform.BaseLineVO;
import java.util.List;
/**
* <p>
*测试表 服务类
* </p>
*
*/
public interface ITestService extends IService<Test> {
List<Test> getAll();
}
5.4 service服务实现
AlarmKindServiceImpl.java
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.xxxx.rest.entity.AlarmKind;
import com.xxxx.rest.mapper.AlarmKindMapper;
import com.xxxx.rest.service.IAlarmKindService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.List;
import java.util.stream.Collectors;
/**
* <p>
* 报警类型表 服务实现类
* </p>
*
*/
@Service
@DS("baseA") //这个注解是指定操作哪个数据源,如果没有这个注解则代表操作配置文件中的主数据源
public class AlarmKindServiceImpl extends ServiceImpl<AlarmKindMapper, AlarmKind> implements IAlarmKindService {
@Resource
private AlarmKindMapper mapper;
@Override
public List<AlarmKind> getAll() {
QueryWrapper<AlarmKind> wrapper=new QueryWrapper();
return mapper.selectList(wwapper);
}
}
TestServiceImpl.java
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.xxxx.rest.entity.Test;
import com.xxxx.rest.mapper.TestMapper;
import com.xxxx.rest.service.ITestService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.List;
import java.util.stream.Collectors;
/**
* <p>
* 测试表 服务实现类
* </p>
*
*/
@Service
@DS("baseB") //这个注解是指定操作哪个数据源,如果没有这个注解则代表操作配置文件中的主数据源
public class TestServiceImpl extends ServiceImpl<TestMapper, Test> implements ITestService {
@Resource
private TestMapper mapper;
@Override
public List<Test> getAll() {
QueryWrapper<Test> wrapper=new QueryWrapper();
return mapper.selectList(wwapper);
}
}
6. 测试及验证
编写测试Controller
@RestController
@RequestMapping("/test")
@CrossOrigin
@Api(tags = "手动测试接口管理")
public class TestController {
@Resource
private IAlarmKindService alarmKindService;
@Resource
private ITestService testService;
//查询报警类型数据
@GetMapping("/getAlarmKindList")
public ResponseEntity<Object> getAlarmKindList(){
return getRespOk(alarmKindService.getAll());
}
//查询测试表数据
@GetMapping("/getTestList")
public ResponseEntity<Object> getTestList(){
return getRespOk(testService.getAll());
}
protected ResponseEntity<Object> getRespOk(Object resData) {
return new ResponseEntity<>(resData, HttpStatus.OK); }
}
启动项目
在浏览器访问
1.报警类型信息接口地址:http://localhost:8085/test/getAlarmKindList,如果返回结果说明正确
2.测试信息接口地址:http://localhost:8085/test/getTestList,如果返回结果说明正确
总结
通过以上内容分析,其实关键就引入架包、修改配置文件、服务的实现类中增加@DS("配置文件中定义的数据源名称"),代码改动可以说非常小。