1.0 MyBatisPlus之多数据源
适用于多种场景:纯粹多库、 读写分离、 一主多从、 混合模式等
场景说明:
我们创建两个库,分别为:mybatis_plus(以前的库不动)与mybatis_plus_1(新建),将mybatis_plus库的product表移动到mybatis_plus_1库,这样每个库一张表,通过一个测试用例分别获取用户数据与商品数据,如果获取到说明多库模拟成功
1.创建数据库及表
创建数据库mybatis_plus_1和表`product
CREATE DATABASE `mybatis_plus_1` /*!40100 DEFAULT CHARACTER SET utf8mb4 */; use `mybatis_plus_1`; CREATE TABLE product ( id BIGINT(20) NOT NULL COMMENT '主键ID', name VARCHAR(30) NULL DEFAULT NULL COMMENT '商品名称', price INT(11) DEFAULT 0 COMMENT '价格', version INT(11) DEFAULT 0 COMMENT '乐观锁版本号', PRIMARY KEY (id) );
2.0 添加测试数据
INSERT INTO product (id, NAME, price) VALUES (1, '外星人笔记本', 100);
3.0 删除mybatis_plus库中的product表
use mybatis_plus; DROP TABLE IF EXISTS product;
2.0 新建工程引入依赖
自行新建一个Spring Boot工程并选择MySQL驱动及Lombok依赖
1.新建工程引入依赖
自行新建一个Spring Boot工程并选择MySQL驱动及Lombok依赖
引入MyBaits-Plus的依赖及多数据源的依赖
<dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.5.1</version> </dependency> <dependency> <groupId>com.baomidou</groupId> <artifactId>dynamic-datasource-spring-boot-starter</artifactId> <version>3.5.0</version> </dependency>
本人全部pom;
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.7.1</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.example</groupId> <artifactId>mybatisplus</artifactId> <version>0.0.1-SNAPSHOT</version> <name>mybatisplus</name> <description>Demo project for Spring Boot</description> <properties> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <!-- <dependency>--> <!-- <groupId>com.baomidou</groupId>--> <!-- <artifactId>mybatis-plus-boot-starter</artifactId>--> <!-- <version>3.3.1</version>--> <!-- </dependency>--> <!-- mybatis-plus核心包--> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.5.1</version> </dependency> <!-- mybatis-plus代码生成核心包 最低3.5.1--> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-generator</artifactId> <version>3.5.1</version> </dependency> <!-- freemarker我们实现的功能使用的freemarker引擎代码--> <dependency> <groupId>org.freemarker</groupId> <artifactId>freemarker</artifactId> <version>2.3.31</version> </dependency> <!-- 多数据源中使用的注解--> <dependency> <groupId>com.baomidou</groupId> <artifactId>dynamic-datasource-spring-boot-starter</artifactId> <version>3.5.0</version> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.29</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <!--防止打war包出错--> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-resources-plugin</artifactId> <version>3.1.0</version> </plugin> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <configuration> <excludes> <exclude> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </exclude> </excludes> </configuration> </plugin> </plugins> </build> </project>
代码层次展示:
2.数据库代码
mybatis_plus_1
CREATE DATABASE `mybatis_plus_1` /*!40100 DEFAULT CHARACTER SET utf8mb4 */; use `mybatis_plus_1`; CREATE TABLE product ( id BIGINT(20) NOT NULL COMMENT '主键ID', name VARCHAR(30) NULL DEFAULT NULL COMMENT '商品名称', price INT(11) DEFAULT 0 COMMENT '价格', version INT(11) DEFAULT 0 COMMENT '乐观锁版本号', PRIMARY KEY (id) ); INSERT INTO product (id, NAME, price) VALUES (1, '外星人笔记本', 100);
mybatis_plus
CREATE DATABASE `mybatis_plus` /*!40100 DEFAULT CHARACTER SET utf8mb4 */; /* Navicat Premium Data Transfer Source Server : 本地mysql Source Server Type : MySQL Source Server Version : 50736 Source Host : localhost:3306 Source Schema : mybatis_plus Target Server Type : MySQL Target Server Version : 50736 File Encoding : 65001 Date: 16/10/2022 20:57:58 */ SET NAMES utf8mb4; SET FOREIGN_KEY_CHECKS = 0; -- ---------------------------- -- Table structure for t_user -- ---------------------------- DROP TABLE IF EXISTS `t_user`; CREATE TABLE `t_user` ( `uid` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID', `user_name` varchar(30) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '姓名', `age` int(11) NULL DEFAULT NULL COMMENT '年龄', `email` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '邮箱', `is_delect` int(255) NULL DEFAULT 0 COMMENT '是否删除', `sex` int(255) NULL DEFAULT NULL COMMENT '性别', PRIMARY KEY (`uid`) USING BTREE ) ENGINE = InnoDB AUTO_INCREMENT = 17 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic; -- ---------------------------- -- Records of t_user -- ---------------------------- INSERT INTO `t_user` VALUES (1, 'Jone', 18, 'test1@baomidou.com', 1, NULL); INSERT INTO `t_user` VALUES (2, 'Jack', 20, 'test2@baomidou.com', 1, NULL); INSERT INTO `t_user` VALUES (4, '我是老王', 18, 'test4@baomidou.com', 0, NULL); INSERT INTO `t_user` VALUES (5, 'Billie', 10, 'test5@baomidou.com', 0, NULL); INSERT INTO `t_user` VALUES (6, '老王', 10, '757631644001', 0, NULL); INSERT INTO `t_user` VALUES (7, '老王超1', 10, '757631644111', 0, NULL); INSERT INTO `t_user` VALUES (8, '闫文超2', 10, '757631644221', 0, NULL); INSERT INTO `t_user` VALUES (9, '闫文超3', 10, '757631644331', 0, NULL); INSERT INTO `t_user` VALUES (10, '闫文超4', 14, '757631644441', 0, NULL); INSERT INTO `t_user` VALUES (11, '闫文超5', 15, '757631644771', 1, NULL); INSERT INTO `t_user` VALUES (12, '闫文超6', 16, '757631644661', 0, NULL); INSERT INTO `t_user` VALUES (13, '闫文超7', 17, '757631644771', 1, NULL); INSERT INTO `t_user` VALUES (14, '我很心烦', 888, '757631644@qq.com', 0, NULL); INSERT INTO `t_user` VALUES (15, '我很心烦', 888, '757631644@qq.com', 0, NULL); INSERT INTO `t_user` VALUES (16, 'admin', 33, NULL, 0, 1); SET FOREIGN_KEY_CHECKS = 1;
2.0 MyBatisPlus之多数据源代码
2.1 创建配置类
application.yml
spring: # 配置数据源信息 datasource: dynamic: # 设置默认的数据源或者数据源组,默认值即为master primary: master # 严格匹配数据源,默认false.true未匹配到指定数据源时抛异常,false使用默认数据源 strict: false datasource: # primary: master 指定的master 就是下面的这个 也就是他就是默认的数据源 master: url: jdbc:mysql://localhost:3306/mybatis_plus?characterEncoding=utf-8&useSSL=false driver-class-name: com.mysql.cj.jdbc.Driver username: root password: root slave_1: url: jdbc:mysql://localhost:3306/mybatis_plus_1?characterEncoding=utf-8&useSSL=false driver-class-name: com.mysql.cj.jdbc.Driver username: root password: root
2.2 创建实体类
- Product
package com.example.mybatisplus.pojo; import lombok.Data; @Data public class Product { //默认字段id 即不需要指定 private Long id; private String name; private Integer price; private Integer version; }
- User
package com.example.mybatisplus.pojo; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import lombok.Data; @Data //指定数据库的表 操作和实际不一样用该注解 @TableName("t_user") public class User { // 指定默认的自增id @TableId private Long uid; private String userName; private Integer age; private String email; private Integer isDelect; private Integer sex; }
2.3 创建Mapper
- ProductMapper
在这里插入代码片
package com.example.mybatisplus.mapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.example.mybatisplus.pojo.Product; import org.springframework.stereotype.Repository; @Repository public interface ProductMapper extends BaseMapper<Product> { }
- UserMapper
package com.example.mybatisplus.mapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.example.mybatisplus.pojo.User; import org.springframework.stereotype.Repository; //防止测试报错故加次注解 @Repository public interface UserMapper extends BaseMapper<User> { }
2.4 创建Service及其ServiceImpl
- ProductService
package com.example.mybatisplus.service; import com.baomidou.mybatisplus.extension.service.IService; import com.example.mybatisplus.pojo.Product; public interface ProductService extends IService<Product> { }
- ProductServiceImpl
package com.example.mybatisplus.service.Impl; import com.baomidou.dynamic.datasource.annotation.DS; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.example.mybatisplus.mapper.ProductMapper; import com.example.mybatisplus.pojo.Product; import com.example.mybatisplus.service.ProductService; import org.springframework.stereotype.Service; @DS("slave_1") @Service public class ProductServiceImpl extends ServiceImpl<ProductMapper, Product> implements ProductService { }
- UserService
package com.example.mybatisplus.service; import com.baomidou.mybatisplus.extension.service.IService; import com.example.mybatisplus.pojo.User; public interface UserService extends IService<User> { }
- UserServiceImpl
package com.example.mybatisplus.service.Impl; import com.baomidou.dynamic.datasource.annotation.DS; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.example.mybatisplus.mapper.UserMapper; import com.example.mybatisplus.pojo.User; import com.example.mybatisplus.service.UserService; import org.springframework.stereotype.Service; //指定数据库表(多数据源中) 对应 yml 中 master 对应的数据库 @DS("master") @Service public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService { }
2.5 启动类修改
MybatisPlusDatasourceApplication指定mapper
package com.example.mybatisplus; import org.mybatis.spring.annotation.MapperScan; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication @MapperScan("com.example.mybatisplus.mapper") public class MybatisPlusDatasourceApplication { public static void main(String[] args) { SpringApplication.run(MybatisPlusDatasourceApplication.class, args); } }
2.6 测试多数据源
新建测试类进行测试;
package com.example.mybatisplus; import com.example.mybatisplus.pojo.Product; import com.example.mybatisplus.pojo.User; import com.example.mybatisplus.service.ProductService; import com.example.mybatisplus.service.UserService; import org.junit.jupiter.api.Test; import org.springframework.boot.test.context.SpringBootTest; import javax.annotation.Resource; @SpringBootTest class MybatisPlusDatasourceApplicationTests { @Resource UserService userService; @Resource ProductService productService; @Test void contextLoads() { User user = userService.getById(1L); Product product = productService.getById(1L); System.out.println("User = " + user); System.out.println("Product = " + product); } }
查询成功说明我们的测试成功;
3.0 知识点扩展
简介
dynamic-datasource-spring-boot-starter 是一个基于springboot的快速集成多数据源的启动器。
官方文档:https://www.kancloud.cn/tracy5546/dynamic-datasource/2264611
特性
- 支持 数据源分组 ,适用于多种场景 纯粹多库 读写分离 一主多从 混合模式。
- 支持数据库敏感配置信息 加密 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的分布式事务方案。
- 提供 本地多数据源事务方案。 附:不能和原生spring事务混用。
约定
1.本框架只做 切换数据源 这件核心的事情,并不限制你的具体操作,切换了数据源可以做任何CRUD。
2.配置文件所有以下划线 _ 分割的数据源 首部 即为组的名称,相同组名称的数据源会放在一个组下。
3.切换数据源可以是组名,也可以是具体数据源名称。组名则切换时采用负载均衡算法切换。
4.默认的数据源名称为 master ,你可以通过 spring.datasource.dynamic.primary 修改。
5.方法上的注解优先于类上注解。
6.DS支持继承抽象类上的DS,暂不支持继承接口上的DS。
使用方法在这里插入代码片
1.引入dynamic-datasource-spring-boot-starter。
<dependency> <groupId>com.baomidou</groupId> <artifactId>dynamic-datasource-spring-boot-starter</artifactId> <version>${version}</version> </dependency>
2.配置数据源。
spring: datasource: dynamic: primary: master #设置默认的数据源或者数据源组,默认值即为master strict: false #严格匹配数据源,默认false. true未匹配到指定数据源时抛异常,false使用默认数据源 datasource: master: url: jdbc:mysql://xx.xx.xx.xx:3306/dynamic username: root password: 123456 driver-class-name: com.mysql.jdbc.Driver # 3.2.0开始支持SPI可省略此配置 slave_1: url: jdbc:mysql://xx.xx.xx.xx:3307/dynamic username: root password: 123456 driver-class-name: com.mysql.jdbc.Driver slave_2: url: ENC(xxxxx) # 内置加密,使用请查看详细文档 username: ENC(xxxxx) password: ENC(xxxxx) driver-class-name: com.mysql.jdbc.Driver #......省略 #以上会配置一个默认库master,一个组slave下有两个子库slave_1,slave_2
# 多主多从 纯粹多库(记得设置primary) 混合配置 spring: spring: spring: datasource: datasource: datasource: dynamic: dynamic: dynamic: datasource: datasource: datasource: master_1: mysql: master: master_2: oracle: slave_1: slave_1: sqlserver: slave_2: slave_2: postgresql: oracle_1: slave_3: h2:
3.使用 @DS 切换数据源
@DS 可以注解在方法上或类上,同时存在就近原则 方法上注解 优先于 类上注解。
注解 | 结果 |
没有@DS | 默认数据源 |
@DS(“dsName”) | dsName可以为组名也可以为具体某个库的名称 |
@Service @DS("slave") public class UserServiceImpl implements UserService { @Autowired private 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"); } }
部分应用官方文档知识点进行扩展;