【SringBoot项目中MyBatis-Plus多数据源应用实践】

文章目录

前言

一、Mybatis-Plus是什么?

二、多数据源是什么?

三、使用步骤

1. 新建一个SpringBoot项目

2. 引入必要的MyBatis架包

3. 新建两个数据库及两张表

3.3.1 新建数据库:DB_A,并创建一张数据表alarm_kind,以及一些测试数据。

3.3.2 同样再建一个数据库DB_B,并创建一张数据表test,以及一些测试数据。

4. 修改配置文件application.yml

5. 编码

5.1 entity 实体类

5.2 mapper接口

5.3 service服务接口

5.4 service服务实现

6. 测试及验证 

总结




前言

在日常大型项目中经常会遇到分库分表的数据库设计,咱们普通的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-basedatasource:dynamic:primary: baseA #默认加载的数据库是DB_Astrict: falsedatasource:baseA:driver-class-name: com.mysql.cj.jdbc.Driver #数据源配置url: jdbc:mysql://127.0.0.1:13306/DB_A?serverTimezone=GMT%2B8&useSSL=falseusername: rootpassword: data@123456!type: com.alibaba.druid.pool.DruidDataSource  #连接池配置max-idle: 10  #No operations allowed after connection closed错误原因及解决max-wait: 10000min-idle: 5initial-size: 5validation-query: SELECT 1test-on-borrow: falsetest-while-idle: truetime-between-eviction-runs-millis: 18800baseB:driver-class-name: com.mysql.cj.jdbc.Driver #数据源配置url: jdbc:mysql:///127.0.0.1:13306/DB_B?serverTimezone=GMT%2B8&useSSL=falseusername: rootpassword: data@123456!type: com.alibaba.druid.pool.DruidDataSource  #连接池配置max-idle: 10  #No operations allowed after connection closed错误原因及解决max-wait: 10000min-idle: 5initial-size: 5validation-query: SELECT 1test-on-borrow: falsetest-while-idle: truetime-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 {@Resourceprivate AlarmKindMapper mapper;@Overridepublic 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 {@Resourceprivate TestMapper mapper;@Overridepublic List<Test> getAll() {QueryWrapper<Test> wrapper=new QueryWrapper();return mapper.selectList(wwapper);}
}


    

6. 测试及验证 

编写测试Controller

@RestController
@RequestMapping("/test")
@CrossOrigin
@Api(tags = "手动测试接口管理")
public class TestController {@Resourceprivate IAlarmKindService alarmKindService;@Resourceprivate 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("配置文件中定义的数据源名称"),代码改动可以说非常小。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/21750.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

云端数据提取:安全、高效地利用无限资源

在当今的大数据时代&#xff0c;企业和组织越来越依赖于云平台存储和处理海量数据。然而&#xff0c;随着数据的指数级增长&#xff0c;数据的安全性和高效的数据处理成为了企业最为关心的议题之一。本文将探讨云端数据安全的重要性&#xff0c;并提出一套既高效又安全的数据提…

浅测 长亭雷池 WAF “动态防护”

本文首发于 Anyeの小站 前言 雷池 WAF 社区版的更新速度是真快啊&#xff0c;几乎一周一个小版本&#xff0c;俩月一个大版本&#xff0c;攻城狮们真的狠啊&#xff0c;没法测了。 废话不多说&#xff0c;前两天看到了 这篇文章&#xff0c;对雷池的“动态防护”功能挺感兴趣…

Android应用的基本构造及威胁(apk)

目录 APK文件是什么 apk文件解压后的目录结构 apk文件的存储位置

去掉el-table表头右侧类名是gutter,width=17px的空白区域(包括表头样式及表格奇偶行样式和表格自动滚动)

代码如下&#xff1a; <el-table:data"tableData"ref"scroll_Table":header-cell-style"getRowClass":cell-style"styleBack"height"350px"style"width: 100%"><el-table-column prop"id" l…

Scrum团队在迭代中如何处理计划外的工作

认为 Scrum 团队不做计划其实是一个误区&#xff0c;实际上很多 Scrum 团队在冲刺计划会议以及在细化工作项时均会进行详细规划。此外&#xff0c;他们还会创建一个路线图&#xff0c;以便显示他们在多个冲刺中的计划。 Scrum 团队需要经常进行计划&#xff0c;以便在不断变化…

linux学习:进程

目录 例子1 获取当前进程的进程标识符 例子2 创建一个新的子进程 例子3 展示了父进程和子进程的进程标识符 例子4 区分父进程和子进程 例子5 区分父进程和子进程的行为 例子6 比较进程标识符来区分父进程和子进程 例子7 子进程如何修改一个变量&…

混合动力电动汽车介绍(二)

接续前一章内容&#xff0c;本篇文章介绍混合动力汽车串联、并联和混联的系统组成和工作原理。 一、串联混合动力电动汽车的系统组成和工作原理 上图为串联混合动力电动汽车的结构简图。汽车由电动机-发电机驱动行驶&#xff0c;电机控制器的动力来自油箱-发动机-发电机-发电机…

Python 爬虫零基础:探索网络数据的神秘世界

Python 爬虫零基础&#xff1a;探索网络数据的神秘世界 在数字化时代&#xff0c;网络数据如同无尽的宝藏&#xff0c;等待着我们去发掘。Python爬虫&#xff0c;作为获取这些数据的重要工具&#xff0c;正逐渐走进越来越多人的视野。对于零基础的学习者来说&#xff0c;如何入…

基于Spring Boot框架的分页查询和文件上传

分页查询 分析 要想从数据库中进行分页查询&#xff0c;我们要使用LIMIT关键字&#xff0c;格式为&#xff1a;limit 开始索引 每页显示的条数 假设一页想展示10条数据 查询第1页数据的SQL语句是&#xff1a; select * from emp limit 0,10; 查询第2页数据的SQL语句是&…

【Pytest官方文档翻译及学习】2.2 如何在测试中编写和报告断言

目录 2.2 如何在测试中编写和报告断言 2.2.1 使用assert语句断言 2.2.2 关于预期异常的断言 2.2.3 关于预期警告的断言 2.2.4 应用上下文相关的比较 2.2.5 为失败的断言定义自己的解释 2.2.6 断言内省细节 2.2 如何在测试中编写和报告断言 2.2.1 使用assert语句断言 p…

6、架构-服务端缓存

为系统引入缓存之前&#xff0c;第一件事情是确认系统是否真的需要缓 存。从开发角度来说&#xff0c;引入缓存会提 高系统复杂度&#xff0c;因为你要考虑缓存的失效、更新、一致性等问题&#xff1b;从运维角度来说&#xff0c;缓存会掩盖一些缺 陷&#xff0c;让问题在更久的…

npm彻底清理缓存

在使用npm过程中&#xff0c;肯定会遇到清缓存的情况&#xff0c;网上的命令一般为 npm cache clear --force有时笔者在清理缓存之后npm install依然失败&#xff0c;仔细发现&#xff0c;执行该命令之后npm报了一个警告 npm WARN using --force Recommended protections dis…

代码随想录算法训练营第27天|● 39. 组合总和● 40.组合总和II● 131.分割回文串

组合总和 题目链接 39. 组合总和 - 力扣&#xff08;LeetCode&#xff09; 代码&#xff1a; class Solution {public List<List<Integer>> res new ArrayList<>();public List<Integer> list new ArrayList<>();public int sum 0;/**…

在nginx中配置反向代理

在nginx中配置反向代理&#xff0c;需要使用proxy_pass指令。以下是一个简单的nginx反向代理配置示例&#xff1a; server {listen 80;server_name example.com;location / {proxy_pass http://backend_server;proxy_set_header Host $host;proxy_set_header X-Real-IP $remote…

LoadRunner 录制脚本时提示无Internet访问/加载慢,如何解决?

LoadRunner 录制脚本时提示无Internet访问/加载慢&#xff0c;如何解决&#xff1f; 在使用LoadRunner 12.02 进行录制脚本时提示无Internet访问&#xff0c;这是如下图&#xff1a; 翻译中文如下&#xff1a; 这里&#xff0c;我认为大家应该都已经点过yes了&#xff0c;但是…

python结构化模式匹配switch-case,Python 3.10中引入,Python的模式匹配(pattern matching)语法

增加了采用模式加上相应动作的 match 语句 和 case 语句 的形式的结构化模式匹配。 模式由序列、映射、基本数据类型以及类实例构成。 模式匹配使得程序能够从复杂的数据类型中提取信息、根据数据结构实现分支&#xff0c;并基于不同的数据形式应用特定的动作。 语法与操作 模…

Linux下配置Pytorch

1.Anaconda 1.1虚拟环境创建 2.Nvidia驱动 3.CUDA驱动安装 4.Pytorch安装 具体的步骤如上&#xff1a;可参考另一位博主的博客非常详细&#xff1a; Linux服务器配置PythonPyTorchCUDA深度学习环境_linux cuda环境配置-CSDN博客https://blog.csdn.net/NSJim/article/detai…

极海APM32F072用Keil5烧录失败Error: Flash Download failed -“Cortex-MO+“

在用Keil5烧录时&#xff0c;出现错误弹窗&#xff0c;大概长这样&#xff1a; 检查了一圈设置&#xff0c;都搞不好。 先用J-Flash&#xff0c;显示读写保护&#xff08;未截图&#xff09;&#xff0c;会跳出界面让选择是否解除读写保护&#xff1a; 1.点击允许读操作YES&am…

DNF手游攻略:0氪攻略,转职技巧与避坑指南!

在DNF手游的冒险旅程中&#xff0c;角色的转职是一次重要的成长经历。通过转职&#xff0c;玩家可以获得全新的技能和属性&#xff0c;提升自己在地下城中的战斗力。本文将为您介绍转职后的关键技巧和日常任务&#xff0c;帮助您更好地适应新的职业身份&#xff0c;成为地下城中…

Python从0到100(二十九):requests模块处理cookie

1 爬虫中使用cookie 为了能够通过爬虫获取到登录后的页面&#xff0c;或者是解决通过cookie的反扒&#xff0c;需要使用request来处理cookie相关的请求 1.1 爬虫中使用cookie的利弊 带上cookie的好处 能够访问登录后的页面能够实现部分反反爬 带上cookie的坏处 一套cookie往往…