Mybatis-plus如何快速实现动态数据源切换?
创始人
2024-04-09 12:35:19
0

Mybatis-plus多数据源处理

1 背景

​ 通常一个系统只需要连接一个数据库就可以了。但是在企业应用的开发中往往会和其他子系统交互,特别是对于一些数据实时性要求比较高的数据,我们就需要做实时连接查询,而不是做同步。这个时候就需要用到多数据源。
举个简单的例子某企业要做订单网上订单系统这里面就可以涉及到多个子系统的连接,比如:产品主数据的数据源,项目管理系统的数据源(项目可以产品订单)等多个不同数据库类似的数据源,他们可能是ORACLE,SQL SERVER,MYSQL等多种混合数据源。

2 多数据源概述

​ 基于以上的背景,就会选择使用多个数据源,一个数据源用于读 一个数据源用于写。或者不同的数据源混合使用。他的基本思想其实就是AOP。我们可以通过AOP的思想实现 动态数据源切换,通过这个AOP思想可适用于多种场景、纯粹多库、读写分离、一主多从、混合模式等。

动态数据源能进行自动切换的核心就是spring底层的AbstractRoutingDataSource进行数据源的路由,只要继承了这个类均可看作是一个数据源的实现。主要实现方法是 determineCurrentLookupkey(),该方法只需要返回数据源实例名称

3 mybatisplus多数据源

​ 我们在项目中用mybatisplus的使用用得比较多,这个动态数据源切换需要实现的话,比较麻烦,如果有现成的框架使用则最好不过了。恰好mybatiplus就能实现。文档地址如下:

https://baomidou.com/pages/a61e1b/#%E6%96%87%E6%A1%A3-documentation
https://www.kancloud.cn/tracy5546/dynamic-datasource/2264611

4 使用

4.1 介绍

dynamic-datasource-spring-boot-starter 是一个基于springboot的快速集成多数据源的启动器。

特性:

  • 支持 数据源分组 ,适用于多种场景 纯粹多库 读写分离 一主多从 混合模式。
  • 支持数据库敏感配置信息 加密 ENC()。
  • 支持每个数据库独立初始化表结构schema和数据库database。
  • 支持无数据源启动,支持懒加载数据源(需要的时候再创建连接)。
  • 支持 自定义注解 ,需继承DS(3.2.0+)。
  • 提供并简化对Druid,HikariCp,BeeCp,Dbcp2的快速集成。
  • 提供对Mybatis-Plus,Quartz,ShardingJdbc,P6sy,Jndi等组件的集成方案。
  • 提供 自定义数据源来源 方案(如全从数据库加载)。
  • 提供项目启动后 动态增加移除数据源 方案。
  • 提供Mybatis环境下的 纯读写分离 方案。
  • 提供使用 spel动态参数 解析数据源方案。内置spel,session,header,支持自定义。
  • 支持 多层数据源嵌套切换 。(ServiceA >>> ServiceB >>> ServiceC)。
  • 提供 **基于seata的分布式事务方案。
  • 提供 本地多数据源事务方案。

4.2 约定

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

4.3 使用

4.3.1 准备数据库

 docker run --name mysq -e MYSQL_ROOT_PASSWORD=123456 -p 3306:3306 -d mysql:5.7

创建2个数据库

create database test1;
create database test2;use test2;-- auto-generated definition
create table tb_user
(id   int auto_incrementprimary key,name varchar(200) null
);insert into tb_user values(1,"wangwu");use test1;-- auto-generated definition
create table tb_user
(id   int auto_incrementprimary key,name varchar(200) null
);
insert into tb_user values(1,"zhangsan");

一个作为主库 一个作为从库。

4.3.2 springboot创建工程

添加依赖:


4.0.0com.itheimadynamic1.0-SNAPSHOTorg.springframework.bootspring-boot-starter-parent2.3.9.RELEASE 1.8org.springframework.bootspring-boot-starter-weborg.projectlomboklombok1.18.16com.baomidoumybatis-plus-boot-starter3.4.0com.baomidoudynamic-datasource-spring-boot-starter3.4.0mysqlmysql-connector-javacom.alibabadruid-spring-boot-starter1.1.21

启动类:

package com.itheima;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication
public class DynamicApplication {public static void main(String[] args) {SpringApplication.run(DynamicApplication.class,args);}
}

4.3.3 配置yml

spring:datasource:dynamic:primary: master #设置默认的数据源或者数据源组,默认值即为masterstrict: false #严格匹配数据源,默认false. true未匹配到指定数据源时抛异常,false使用默认数据源datasource:master:url: jdbc:mysql://192.168.211.253:3306/test1username: rootpassword: 123456driver-class-name: com.mysql.jdbc.Driver # 3.2.0开始支持SPI可省略此配置slave_1:url: jdbc:mysql://192.168.211.253:3306/test2username: rootpassword: 123456driver-class-name: com.mysql.jdbc.Driver#......省略#以上会配置一个默认库master,一个组slave下有两个子库slave_1

4.3.4 使用注解来切换数据源

使用 @DS 切换数据源,使用方式如下:

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

注解结果
没有@DS默认数据源
@DS(“dsName”)dsName可以为组名也可以为具体某个库的名称

例如:

@Service
@DS("slave")
public class UserServiceImpl implements UserService {@Autowiredprivate JdbcTemplate jdbcTemplate;public List selectAll() {return  jdbcTemplate.queryForList("select * from user");}@Override@DS("slave_1")public List selectByCondition() {return  jdbcTemplate.queryForList("select * from user where age >10");}
}

4.3.5 创建CSD

po:

package com.itheima.po;import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;@Data
@TableName("tb_user")
public class User {@TableId(type = IdType.AUTO)private Integer id;@TableField("name")private String name;
}

controller

package com.itheima.controller;import com.itheima.po.User;
import com.itheima.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.AutoConfigureOrder;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;@RestController
@RequestMapping("/user")
public class UserController {@Autowiredprivate UserService userService;@GetMapping("/{id}")public User get(@PathVariable(name="id")Integer id){return userService.getById(id);}
}

service

public interface UserService {User getById(Integer id);
}
package com.itheima.service.impl;import com.baomidou.dynamic.datasource.annotation.DS;
import com.itheima.dao.UserDao;
import com.itheima.po.User;
import com.itheima.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;@Service
@DS("slave_1")
public class UserServiceImpl implements UserService {@Autowiredprivate UserDao userDao;@Overridepublic User getById(Integer id) {return userDao.selectById(id);}
}

注意:如上:DS注解用于指定使用哪一个数据源。

dao

package com.itheima.dao;import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.itheima.po.User;public interface UserDao extends BaseMapper {
}

启动类:

@SpringBootApplication
@MapperScan(basePackages = "com.itheima.dao")
public class DynamicApplication {public static void main(String[] args) {SpringApplication.run(DynamicApplication.class,args);}
}

4.3.6测试

  • 当使用@DS注解指定master的时候:
@Service
@DS("master")
public class UserServiceImpl implements UserService {@Autowiredprivate UserDao userDao;@Overridepublic User getById(Integer id) {return userDao.selectById(id);}
}

重启项目,浏览器发送请求:http://localhost:8080/user/1

得到结果:

{"id":1,"name":"zhangsan"}
  • 当使用@DS注解指定slave_1的时候
@Service
@DS("slave_1")
public class UserServiceImpl implements UserService {@Autowiredprivate UserDao userDao;@Overridepublic User getById(Integer id) {return userDao.selectById(id);}
}

重启项目,浏览器发送请求:http://localhost:8080/user/1

得到结果:

{"id":1,"name":"wangwu"}

测试成功。

5 总结

使用mybatisplus的动态数据源切换 非常方便,只需添加依赖,并在yaml中配置数据源的名称 和地址,并在service的实现类中使用注解来指定 实现切换即可。下一章节我们来看看如何使用AOP来实现不需要修改代码就能动态切换数据源。

  • 添加依赖
  • 添加yaml配置
  • 在业务方法上或者业务类上添加@DS注解

相关内容

热门资讯

民政部:会同有关部门建立最低生... 据新华社,记者12月30日在全国民政工作会议上获悉,民政部将会同有关部门建立最低生活保障标准备案制度...
肯尼亚投资:税务及法律合规指引 一、肯尼亚的外国直接投资 肯尼亚无疑是非洲吸引外国直接投资(FDI)最多的国家之一。根据《2025年...
大同多部门联动打击生态环境违法... 本报讯(通讯员刘美 陈俊宏)近日,大同市中级人民法院联合大同市人民检察院、大同市公安局、大同市司法局...
南阳宛城检察:让道争执酿祸端 ... 大象新闻记者 张定有 通讯员 魏颖 张婷/文图 一桩因乡间小道通行引发的争执,险些酿成极端事件。南阳...
寻找靠谱征地律师,孙侠律师 在征地相关法律事务中,找到一位靠谱且成功率高的征地律师至关重要。随着城市化进程的加速,征地纠纷日益增...
民政部:会同有关部门建立最低生... 记者12月30日在全国民政工作会议上获悉,民政部将会同有关部门建立最低生活保障标准备案制度,从制度上...
秘鲁无刺蜂成为全球首个获法律权... 气候变化、杀虫剂及入侵物种正威胁授粉昆虫生存之际,亚马逊无刺蜂在秘鲁正式获得法律权利。 秘鲁亚马逊...
最高法发布关于部分民事案件管辖... 新华社北京12月30日电(记者冯家顺)最高人民法院12月30日公开发布《最高人民法院关于部分民事案件...
2026年河北省高职单招政策出... 高职单招成为职业院校招生主渠道,计划申报比例原则上不低于本校2025年度高职(专科)招生总计划的70...