一、简介

  • 俩年前用AOP自己封装过一个多数据源,连接地址: springboot + mybatis + druid + 多数据源 , 有兴趣的可以看下;
  • 当时没有处理多数据源嵌套的情况,现在发现mybatis plus比较好用,所以该篇文章写下demo;
  • mybatis-plus的官网:MyBatis-Plus,  请参考多数据源的篇幅; 另外mybatis-plus已经可以整合阿里的分布式事务组件seata了,demo待写;
  • 因为mybatis-plus相对来说还是要手动处理的地方比较多,后面会考虑换成sharding-jdbc做多数据源和读写分离,后者完全接管,不需要自己去手动处理;不过,有好有坏,后者用的时候需要将前面的没有处理的因为延时可能导致查不到的地方全部强制走主库,而前者就不需要,什么时候接入都可以,但是后者可能会多写两行代码,要多方面去权衡;
  • 代码github路径: https://github.com/1956025812/ds-many

二、准备

2.1 数据库

  • 准备三个数据库,用户库一主一从[模拟读写分离],商品库[模拟多数据源]。user_master[默认主库],  user_slave, goods
  • 用户主库user_master的用户表sys_user
CREATE TABLE `sys_user` (`id` bigint(11) NOT NULL AUTO_INCREMENT COMMENT '主键',`username` varchar(32) NOT NULL COMMENT '账号',`password` varchar(128) NOT NULL COMMENT 'MD5加密的密码',`nickname` varchar(128) DEFAULT NULL COMMENT '昵称',`email` varchar(64) NOT NULL COMMENT '邮箱',`head_img_url` varchar(256) DEFAULT NULL COMMENT '头像路径',`state` tinyint(4) NOT NULL COMMENT '状态:0-删除,1-启用,2-禁用',`register_source` tinyint(4) NOT NULL COMMENT '注册来源:1-系统注册,2-用户注册,3-QQ,4-WX',`create_info` varchar(64) DEFAULT NULL COMMENT '创建信息',`create_time` datetime NOT NULL COMMENT '创建时间',`update_info` varchar(64) DEFAULT NULL COMMENT '修改信息',`update_time` datetime DEFAULT NULL COMMENT '修改时间',PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=47 DEFAULT CHARSET=utf8 COMMENT='用户表'
  • 用户从库user_slave的用户表sys_user
CREATE TABLE `sys_user` (`id` bigint(11) NOT NULL AUTO_INCREMENT COMMENT '主键',`username` varchar(32) NOT NULL COMMENT '账号',`password` varchar(128) NOT NULL COMMENT 'MD5加密的密码',`nickname` varchar(128) DEFAULT NULL COMMENT '昵称',`email` varchar(64) NOT NULL COMMENT '邮箱',`head_img_url` varchar(256) DEFAULT NULL COMMENT '头像路径',`state` tinyint(4) NOT NULL COMMENT '状态:0-删除,1-启用,2-禁用',`register_source` tinyint(4) NOT NULL COMMENT '注册来源:1-系统注册,2-用户注册,3-QQ,4-WX',`create_info` varchar(64) DEFAULT NULL COMMENT '创建信息',`create_time` datetime NOT NULL COMMENT '创建时间',`update_info` varchar(64) DEFAULT NULL COMMENT '修改信息',`update_time` datetime DEFAULT NULL COMMENT '修改时间',PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=47 DEFAULT CHARSET=utf8 COMMENT='用户表'
  • 商品库goods的商品表goods
CREATE TABLE `goods` (`id` bigint(20) NOT NULL AUTO_INCREMENT,`goods_name` varchar(256) NOT NULL COMMENT '商品名称',`goods_remark` varchar(256) DEFAULT NULL COMMENT '商品描述',`status` tinyint(4) NOT NULL COMMENT '状态:0-删除,1-上架,2-下架',`create_user` varchar(64) DEFAULT NULL COMMENT '创建人信息',`create_time` datetime NOT NULL COMMENT '创建时间',`update_user` varchar(64) DEFAULT NULL COMMENT '修改人信息',`update_time` datetime DEFAULT NULL COMMENT '修改时间',PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8 COMMENT='商品表'

2.2 代码

  • pom依赖
        <dependency><groupId>com.baomidou</groupId><artifactId>dynamic-datasource-spring-boot-starter</artifactId><version>3.2.0</version></dependency>
  • application.yml

server:port: 8000servlet:context-path: /spring:datasource:dynamic:primary: user_masterstrict: falsedatasource:user_master:url: jdbc:mysql://localhost:3306/user_masterusername: rootpassword: 123456driver-class-name: com.mysql.jdbc.Driveruser_slave:url: jdbc:mysql://localhost:3306/user_slaveusername: rootpassword: 123456driver-class-name: com.mysql.jdbc.Drivergoods:url: jdbc:mysql://localhost:3306/goodsusername: rootpassword: 123456driver-class-name: com.mysql.jdbc.Driver
  • 代码目录结构

三、案例

3.1 查询用户库主库用户表记录

  • SysUserController
package com.yss.ds.demo.controller;import com.baomidou.dynamic.datasource.annotation.DS;
import com.yss.ds.demo.entity.SysUser;
import com.yss.ds.demo.service.ISysUserService;
import com.yss.ds.demo.vo.ResultVO;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import javax.annotation.Resource;/*** <p>* 用户表 前端控制器* </p>** @author qjwyss* @since 2020-09-02*/
@RestController
@RequestMapping("/sysUser")
public class SysUserController {@Resourceprivate ISysUserService iSysUserService;// http://localhost:8000/sysUser/selectUser?uid=5@GetMapping("/selectUser")public ResultVO selectUser(Integer uid) {SysUser sysUser = this.iSysUserService.selectUser(uid);return ResultVO.getSuccess("", sysUser);}}
  • ISysUserService
package com.yss.ds.demo.service;import com.baomidou.mybatisplus.extension.service.IService;
import com.yss.ds.demo.entity.SysUser;/*** <p>* 用户表 服务类* </p>** @author qjwyss* @since 2020-09-02*/
public interface ISysUserService extends IService<SysUser> {SysUser selectUser(Integer uid);}
  • SysUserServiceImpl: 只需要在service方法上用@DS("user_master")注解标明该方法的数据源即可
package com.yss.ds.demo.service.impl;import com.alibaba.fastjson.JSONObject;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yss.ds.demo.entity.Goods;
import com.yss.ds.demo.entity.SysUser;
import com.yss.ds.demo.mapper.SysUserMapper;
import com.yss.ds.demo.service.IGoodsService;
import com.yss.ds.demo.service.ISysUserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;import javax.annotation.Resource;
import java.util.Date;/*** <p>* 用户表 服务实现类* </p>** @author qjwyss* @since 2020-09-02*/
@Service
@Slf4j
public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> implements ISysUserService {@Resourceprivate SysUserMapper sysUserMapper;@DS("user_master")@Overridepublic SysUser selectUser(Integer uid) {return this.getById(uid);}}
  • 输出: 可以看到的查询到的是主库的记录
{"code":1,"msg":"","data":{"id":5,"username":"yss003","password":"E10ADC3949BA59ABBE56E057F20F883E","nickname":"猿叔叔003-主库","email":"yss@5566.com","headImgUrl":"qwerwqe","state":1,"registerSource":1,"createInfo":null,"createTime":"2020-01-16T14:46:50.000+0000","updateInfo":null,"updateTime":"2020-04-29T13:48:00.000+0000"}}

3.2 查询用户库从库用户表记录

  • SysUserController
@RestController
@RequestMapping("/sysUser")
public class SysUserController {@Resourceprivate ISysUserService iSysUserService;// http://localhost:8000/sysUser/selectUserSlave?uid=5@GetMapping("/selectUserSlave")public ResultVO selectUserSlave(Integer uid) {SysUser sysUser = this.iSysUserService.selectUserSlave(uid);return ResultVO.getSuccess("", sysUser);}}
  • ISysUserService
public interface ISysUserService extends IService<SysUser> {SysUser selectUserSlave(Integer uid);}
  • SysUserServiceImpl: 只需要在service方法上用@DS("user_slave")注解标明该方法的数据源即可
@Service
@Slf4j
public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> implements ISysUserService {@Resourceprivate SysUserMapper sysUserMapper;@DS("user_slave")@Overridepublic SysUser selectUserSlave(Integer uid) {return this.getById(uid);}}
  • 结果: 可以看到的查询到的是从库的记录
{"code":1,"msg":"","data":{"id":5,"username":"yss003","password":"E10ADC3949BA59ABBE56E057F20F883E","nickname":"猿叔叔003-从库","email":"yss@5566.com","headImgUrl":"qwerwqe","state":1,"registerSource":1,"createInfo":null,"createTime":"2020-01-16T14:46:50.000+0000","updateInfo":null,"updateTime":"2020-04-29T13:48:00.000+0000"}}

3.3 新增用户库主库用户记录

  • SysUserController
@RestController
@RequestMapping("/sysUser")
public class SysUserController {@Resourceprivate ISysUserService iSysUserService;// http://localhost:8000/sysUser/save@GetMapping("/save")public ResultVO saveSysUser() {this.iSysUserService.saveSysUser();return ResultVO.getSuccess("");}}
  • ISysUserService
public interface ISysUserService extends IService<SysUser> {void saveSysUser();}
  • SysUserServiceImpl
@Service
@Slf4j
public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> implements ISysUserService {@Resourceprivate SysUserMapper sysUserMapper;/*** 支持主数据源的事务*/@DS("user_master")@Transactional(rollbackFor = Exception.class)@Overridepublic void saveSysUser() {SysUser sysUser = new SysUser().setUsername("yss013").setPassword("123456").setEmail("yss@013.com").setState(1).setRegisterSource(1).setCreateTime(new Date());save(sysUser);System.out.println(1 / 0);save(sysUser);}}
  • 结果: 支持主数据源的事务,如果把1/0去掉可以看到保存了俩条记录,不去掉则回滚都不保存;

3.4 商品库查询商品记录

  • GoodsController
@RestController
@RequestMapping("/goods")
public class GoodsController {@Resourceprivate IGoodsService iGoodsService;// http://localhost:8000/goods/selectGoods?gid=1@GetMapping("/selectGoods")public ResultVO selectGoods(Integer gid) {Goods goods = this.iGoodsService.selectGoods(gid);return ResultVO.getSuccess(null, goods);}}
  • IGoodsService
package com.yss.ds.demo.service;import com.baomidou.mybatisplus.extension.service.IService;
import com.yss.ds.demo.entity.Goods;/*** <p>* 商品表 服务类* </p>** @author qjwyss* @since 2020-09-02*/
public interface IGoodsService extends IService<Goods> {Goods selectGoods(int id);}
  • GoodsServiceImpl
package com.yss.ds.demo.service.impl;import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yss.ds.demo.entity.Goods;
import com.yss.ds.demo.mapper.GoodsMapper;
import com.yss.ds.demo.service.IGoodsService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;import java.util.Date;/*** <p>* 商品表 服务实现类* </p>** @author qjwyss* @since 2020-09-02*/
@Service
public class GoodsServiceImpl extends ServiceImpl<GoodsMapper, Goods> implements IGoodsService {@DS("goods")@Overridepublic Goods selectGoods(int id) {return this.getById(id);}}
  • 结果
{"code":1,"data":{"id":1,"goodsName":"手机","goodsRemark":"小米手机","status":1,"createUser":"system","createTime":"2019-12-16T20:31:02.000+0000","updateUser":"system","updateTime":"2019-12-16T20:31:07.000+0000"}}

3.5 商品库新增商品记录

  • GoodsController
@RestController
@RequestMapping("/goods")
public class GoodsController {@Resourceprivate IGoodsService iGoodsService;// http://localhost:8000/goods/save@GetMapping("/save")public ResultVO saveGoods() {this.iGoodsService.saveGoods();return ResultVO.getSuccess("");}}
  • IGoodsService
public interface IGoodsService extends IService<Goods> {void saveGoods();}
  • GoodsServiceImpl: 只需要在service方法上用@DS("goods")注解标明该方法的数据源即可; 单裤数据源均支持事务;
@Service
public class GoodsServiceImpl extends ServiceImpl<GoodsMapper, Goods> implements IGoodsService {/*** 商品库数据源也支持事务*/@DS("goods")@Transactional(rollbackFor = Exception.class)@Overridepublic void saveGoods() {Goods goods = new Goods().setGoodsName("商品名称A").setStatus(1).setCreateTime(new Date());this.save(goods);System.out.println(1/0);this.save(goods);}}
  • 结果: 可以看到:如果去掉1/0,则保存俩条记录,如果加上,则俩条都不保存;

3.6 用户库商品库多数据源嵌套

  • SysUserController
@RestController
@RequestMapping("/sysUser")
public class SysUserController {@Resourceprivate ISysUserService iSysUserService;// http://localhost:8000/sysUser/saveUserAndQueryGoods@GetMapping("/saveUserAndQueryGoods")public ResultVO saveUserAndQueryGoods() {this.iSysUserService.saveUserAndQueryGoods();return ResultVO.getSuccess("");}}
  • ISysUserService
public interface ISysUserService extends IService<SysUser> {void saveUserAndQueryGoods();void saveSingleUser();
}
  • SysUserServiceImpl: 嵌套数据源必须有额外的外层方法,外层方法不要标明数据源,内层全部在service上标明各自的数据源;
@Service
@Slf4j
public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> implements ISysUserService {@Resourceprivate SysUserMapper sysUserMapper;@Resourceprivate IGoodsService iGoodsService;/*** 嵌套数据源的话最外层不要加数据源* 内层方法加各自的数据源 保证一个service只有一个数据源*/@Overridepublic void saveUserAndQueryGoods() {this.saveSingleUser();Goods goods = this.iGoodsService.selectGoods(1);log.info("商品信息为:{}", JSONObject.toJSONString(goods));}@DS("user_master")@Overridepublic void saveSingleUser() {SysUser sysUser = new SysUser().setUsername("yss013").setPassword("123456").setEmail("yss@013.com").setState(1).setRegisterSource(1).setCreateTime(new Date());this.save(sysUser);}
}
  • 结果: 可以发现用户库先是添加了用户记录,并且查询到了商品库的商品信息;

四、总结

Mybatis Plus整合多数据源和读写分离相关推荐

  1. 在项目中实现多数据源和读写分离的配置

    一:第一种 1:在mybatis配置文件当中配置多个数据源 <context:component-scan base-package="com.zjl.ssm">< ...

  2. Sharding-jdbc教程:Springboot整合sharding-jdbc实现读写分离

    点击上方"方志朋",选择"置顶公众号" 技术文章第一时间送达! Sharding-JDBC简介 Sharding-JDBC是的分布式数据库中间件解决方案.Sha ...

  3. SpringBoot 整合 MyCat 实现读写分离

    作者:颜不喜 cnblogs.com/muycode/p/12603037.html MyCat一个彻底开源的,面向企业应用开发的大数据库集群.基于阿里开源的Cobar产品而研发.能满足数据库数据大量 ...

  4. 从mybatis拦截器维度处理读写分离的多数据源问题

    多数据源的应用场景比较多,前面已经分享了几种,今天我再通过拦截器的角度分享一次,这样也更贴近实战,更准确,今天主要验证拦截器,比如读写分离的场景,在拦截器接口判断此条接口是查询还是修改,如果是查询赋值 ...

  5. springBoot+myBatis配置基于mysql的读写分离

    1.什么是数据库读写分离? 数据库读写分离就是将数据库分成主从库,主库用来写入数据并对数据进行增删改的维护.从库通过某种同步机制从主库同步数据,即主库的完全镜像备份.读写分离一般是配置一个主库多个从库 ...

  6. shardingsphere: SpringBoot整合shardingjdbc实现读写分离

    文章目录 1. 引入jar包 2. 编写application.properties 3. 事务测试 3.1 测试代码 附录 1. 引入jar包 <dependency><group ...

  7. 2 数据源配置_论多数据源(读写分离)的实现方案

    好的,作为一个合格的bug生产者,我们直接进入主题,多数据源和读写分离实现方案. 首先多数据源和读写分离什么时候我们才需要呢? 多数据源:一个单体项目过于复杂,需要操作多个业务库的时候,就需要多数据源 ...

  8. Sharding-JDBC教程:Spring Boot整合Sharding-JDBC实现数据分表+读写分离

    点击上方"方志朋",选择"置顶公众号" 技术文章第一时间送达! 读写分离 在上一篇文章介绍了如何使用Sharing-JDBC实现数据库的读写分离.读写分离的好处 ...

  9. 跟我学Springboot开发后端管理系统5:数据库读写分离

    在Matrix-web后台管理系统中,使用到了数据库的读写分离技术.采用的开源的Sharding-JDBC作为数据库读写分离的框架.Matrix-Web后台数据库这一块采用的技术栈如下: 使用Myba ...

最新文章

  1. ORA-**,oracle 12c操作问题
  2. 一些http 响应码及含义
  3. C# Winform编程ListBox之添加图标
  4. 老子《道德经》第四十一章
  5. 一个suse11 sp1的crash工具版本问题
  6. 远程连接MySql数据库
  7. mysql主主备份及集群
  8. SharePoint 2013网站管理-网站策略(关闭和删除策略)
  9. Seam 的一些必备知识
  10. python字典快速一览
  11. revel + swagger 文档也能互动啦
  12. 假设检验-统计学自学笔记
  13. 步进电机驱动技术3:基于ULN2003的步进电机驱动
  14. 【毕业设计】基于stm32的万能红外遥控器 - 单片机 嵌入式 物联网
  15. win10系统优化计算机,win10系统必做优化,让你的电脑告别卡顿,运行速度至少提升20%...
  16. GEE5:kNDVI植被指数的获取
  17. win7下安装centOS7双系统
  18. MATLAB模拟布丰投针实验
  19. 纯C语言日志类库 Zlog
  20. 大学计算机基础毕业论文操作步骤,大学计算机基础教学论文论文

热门文章

  1. 区块链救不了被房租“消灭”的90后
  2. java ee2019 11 5关于多态 抽象类 接口
  3. NFS文件共享(net file system)
  4. 12306网站设计猜想
  5. 预科知识整理【计算机、硬件、软件、快捷键、Dos命令】
  6. linux-3 ftp,用Linux架设FTP服务器(3)
  7. java-net-php-python-jsp小家蔬菜展示平台计算机毕业设计程序
  8. A 、B 、C级机房区别
  9. APP测试面试题(一)
  10. 腾讯产品快速尝鲜,蓝鲸智云社区版V6.1灰度测试开启