简单几步学会使用多数据源
前言
我们在日常的工作中肯定会遇到一种情况,一个服务的数据存在数据库A,另一个服务的数据存在数据库B,而我们需要去对这两个服务的数据进行整合,那么除了微服务之外我们还有一种实现思路:多数据源。
简介
dynamic-datasource
是一款开箱即用的轻量级开源框架,主要用于解决动态数据源切换的问题。该框架使用简单,支持多种数据库类型,可以按需配置数据源,只需要简单的几个步骤就可以实现多数据源动态切换。
使用
引入依赖
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.3.1</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.33</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>dynamic-datasource-spring-boot-starter</artifactId>
<version>3.6.1</version>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.19</version>
</dependency>
配置
在这里为了演示就指定到同一个数据源下的不同数据库,我们可以创建一个单独的配置文件来管理我们的数据源,接着我们建立一个 application-druid.yml
的配置文件,如下所示:
spring:
datasource:
dynamic:
# 指定主数据源
primary: user
# 是否启用数据源严格匹配,默认为false,使用默认数据源
# 当其为true时未匹配到指定数据源会报错
strict: false
# 懒加载
lazy: true
datasource:
# 主数据源配置
master_1:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql:///user?useSSL=false&useUnicode=true&characterEncoding=UTF8&serverTimezone=Asia/Shanghai
username: root
password: root
# 从数据源配置
slave_1:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql:///order?useSSL=false&useUnicode=true&characterEncoding=UTF8&serverTimezone=Asia/Shanghai
username: root
password: root
之后我们再在 application.yml
中指定到我们的数据源配置启动
spring:
profiles:
active: druid
此时来测试一下启动,如果控制台出现以下信息就说明我们已经集成成功
测试
集成成功之后我们来使用并测试一下是否有效
假设现在我们有这么一个场景:在数据库 user
中存放着我们的用户服务相关的表,而在数据库 order
中存放着我们订单服务相关的表,我们想要有个接口来 实现查询每个用户下的所有订单。
创建表
数据库 user
中的表
/*
Navicat Premium Data Transfer
Source Server : localhost
Source Server Type : MySQL
Source Server Version : 80032 (8.0.32)
Source Host : localhost:3306
Source Schema : dynamic1
Target Server Type : MySQL
Target Server Version : 80032 (8.0.32)
File Encoding : 65001
Date: 22/07/2023 18:06:44
*/
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for sys_user
-- ----------------------------
DROP TABLE IF EXISTS `sys_user`;
CREATE TABLE `sys_user` (
`user_id` int NOT NULL AUTO_INCREMENT COMMENT '用户id',
`username` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '用户名',
`password` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '密码',
`nickname` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '昵称',
`create_user_id` int NULL DEFAULT NULL COMMENT '创建用户id',
`create_user_name` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '创建用户名称',
`create_time` datetime NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_user_id` int NULL DEFAULT NULL COMMENT '最后修改用户id',
`update_user_name` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '最后修改用户名称',
`update_time` datetime NULL DEFAULT NULL COMMENT '最后修改时间',
PRIMARY KEY (`user_id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of sys_user
-- ----------------------------
INSERT INTO `sys_user` VALUES (1, 'zhagnsan', '123456', '张三', 0, '超级管理员', '2023-07-22 17:20:20', NULL, NULL, NULL);
INSERT INTO `sys_user` VALUES (2, 'lisi', '123456', '李四', 0, '超级管理员', '2023-07-22 17:20:32', NULL, NULL, NULL);
SET FOREIGN_KEY_CHECKS = 1;
数据库 order
中的表
/*
Navicat Premium Data Transfer
Source Server : localhost
Source Server Type : MySQL
Source Server Version : 80032 (8.0.32)
Source Host : localhost:3306
Source Schema : dynamic2
Target Server Type : MySQL
Target Server Version : 80032 (8.0.32)
File Encoding : 65001
Date: 22/07/2023 18:06:49
*/
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for t_order
-- ----------------------------
DROP TABLE IF EXISTS `t_order`;
CREATE TABLE `t_order` (
`order_id` int NOT NULL AUTO_INCREMENT COMMENT '订单id',
`order_num` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '订单号',
`order_name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '订单名称',
`create_user_id` int NULL DEFAULT NULL COMMENT '创建用户id',
`create_user_name` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '创建用户名称',
`create_time` datetime NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_user_id` int NULL DEFAULT NULL COMMENT '最后修改用户id',
`update_user_name` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '最后修改用户名称',
`update_time` datetime NULL DEFAULT NULL COMMENT '最后修改时间',
PRIMARY KEY (`order_id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 6 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of t_order
-- ----------------------------
INSERT INTO `t_order` VALUES (1, 'UzRs_20230722145842008', '手机', 1, '张三', '2023-07-22 17:21:49', NULL, NULL, NULL);
INSERT INTO `t_order` VALUES (2, 'AZps_20230722145842114', '电脑', 1, '张三', '2023-07-22 17:21:49', NULL, NULL, NULL);
INSERT INTO `t_order` VALUES (3, 'ZawS_20230722145843576', '平板', 1, '张三', '2023-07-22 17:21:49', NULL, NULL, NULL);
INSERT INTO `t_order` VALUES (4, 'YxIo_20230722145857663', '薯片', 2, '李四', '2023-07-22 17:21:49', NULL, NULL, NULL);
INSERT INTO `t_order` VALUES (5, 'ZcxY_20230722153244094', '手机', 2, '李四', '2023-07-22 17:21:49', NULL, NULL, NULL);
SET FOREIGN_KEY_CHECKS = 1;
代码实现
在创建完表之后,我们可以使用 Mybaits Plus
的代码生成器将这两个表的代码生成出来,生成后的结构如下:
然后我们在 t_order
表的 Mapper 和 Service 上加上一个注解:@DS(“order”)
,在 sys_user
表的 Mapper 和 Service 上加上一个注解:@DS(“user”)
。
在 dynamic 中,我们就是通过@DS("数据源名称")
注解来实现数据源的切换的。
加完注解后如下:
然后我们就可以开始写我们的业务代码了,首先我们先创建一个 VO 来保存我们的信息
VO
import com.dynamic.module.order.entity.Order;
import com.dynamic.module.user.entity.User;
import lombok.Data;
import java.util.List;
/**
* @author Bummon
* @description
* @date 2023-07-22 17:41
*/
@Data
public class UserOrderVO extends User {
/**
* 订单列表
*/
private List<Order> orderList;
}
Controller
import com.dynamic.module.user.service.UserService;
import com.dynamic.module.user.vo.UserOrderVO;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
/**
* @author Bummon
* @description 用户管理
* @date 2023-07-22 17:40
*/
@RestController
@RequiredArgsConstructor
@RequestMapping("/user")
public class UserController {
private final UserService userService;
@GetMapping("/order")
public List<UserOrderVO> getUserOrderList() {
return userService.getUserOrderList();
}
}
Service
import com.dynamic.module.user.entity.User;
import com.baomidou.mybatisplus.extension.service.IService;
import com.dynamic.module.user.vo.UserOrderVO;
import java.util.List;
/**
* @author Bummon
* @description 针对表【sys_user】的数据库操作Service
* @createDate 2023-07-22 17:06:15
*/
public interface UserService extends IService<User> {
/**
* @return {@link List< UserOrderVO>}
* @date 2023-07-22 17:42
* @author Bummon
* @description 查询用户订单列表
*/
List<UserOrderVO> getUserOrderList();
}
ServiceImpl
import cn.hutool.core.bean.BeanUtil;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.dynamic.module.order.entity.Order;
import com.dynamic.module.order.mapper.OrderMapper;
import com.dynamic.module.user.entity.User;
import com.dynamic.module.user.mapper.UserMapper;
import com.dynamic.module.user.service.UserService;
import com.dynamic.module.user.vo.UserOrderVO;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* @author Bummon
* @description 针对表【sys_user】的数据库操作Service实现
* @createDate 2023-07-22 17:06:15
*/
@DS("user")
@Service
@RequiredArgsConstructor
public class UserServiceImpl extends ServiceImpl<UserMapper, User>
implements UserService {
private final OrderMapper orderMapper;
@Override
public List<UserOrderVO> getUserOrderList() {
List<User> userList = this.list();
List<UserOrderVO> userOrderList = BeanUtil.copyToList(userList, UserOrderVO.class);
userOrderList.forEach(user -> {
List<Order> orderList = orderMapper.selectList(Wrappers.lambdaQuery(Order.class)
.eq(Order::getCreateUserId, user.getUserId()));
user.setOrderList(orderList);
});
return userOrderList;
}
}
测试
代码编写完成之后,我们使用 Postman 来测试一下得到的是否是我们预期的结果
最终得到的结果如下:
[
{
"userId": 1,
"username": "zhagnsan",
"password": "123456",
"nickname": "张三",
"createUserId": 0,
"createUserName": "超级管理员",
"createTime": "2023-07-22T09:20:20.000+00:00",
"updateUserId": null,
"updateUserName": null,
"updateTime": null,
"orderList": [
{
"orderId": 1,
"orderNum": "UzRs_20230722145842008",
"orderName": "手机",
"createUserId": 1,
"createUserName": "张三",
"createTime": "2023-07-22T09:21:49.000+00:00",
"updateUserId": null,
"updateUserName": null,
"updateTime": null
},
{
"orderId": 2,
"orderNum": "AZps_20230722145842114",
"orderName": "电脑",
"createUserId": 1,
"createUserName": "张三",
"createTime": "2023-07-22T09:21:49.000+00:00",
"updateUserId": null,
"updateUserName": null,
"updateTime": null
},
{
"orderId": 3,
"orderNum": "ZawS_20230722145843576",
"orderName": "平板",
"createUserId": 1,
"createUserName": "张三",
"createTime": "2023-07-22T09:21:49.000+00:00",
"updateUserId": null,
"updateUserName": null,
"updateTime": null
}
]
},
{
"userId": 2,
"username": "lisi",
"password": "123456",
"nickname": "李四",
"createUserId": 0,
"createUserName": "超级管理员",
"createTime": "2023-07-22T09:20:32.000+00:00",
"updateUserId": null,
"updateUserName": null,
"updateTime": null,
"orderList": [
{
"orderId": 4,
"orderNum": "YxIo_20230722145857663",
"orderName": "薯片",
"createUserId": 2,
"createUserName": "李四",
"createTime": "2023-07-22T09:21:49.000+00:00",
"updateUserId": null,
"updateUserName": null,
"updateTime": null
},
{
"orderId": 5,
"orderNum": "ZcxY_20230722153244094",
"orderName": "手机",
"createUserId": 2,
"createUserName": "李四",
"createTime": "2023-07-22T09:21:49.000+00:00",
"updateUserId": null,
"updateUserName": null,
"updateTime": null
}
]
}
]
可以看到结果确实为我们预期的结果。
至此,教程就结束啦,感谢大家的关注
推荐
关注博客和公众号获取最新文章
Bummon's Blog | Bummon's Home | 公众号