发布于2024-11-02 12:03 阅读(462) 评论(0) 点赞(11) 收藏(4)
项目需要实现在多个数据源之间读写数据,例如在 A 数据源和 B 数据源读取数据,然后在 C 数据源写入数据 或者 部分业务数据从 A 数据源中读取、部分从B数据源中读取诸如此类需求。本文将简单模拟在SpringBoot项目中实现不同数据源之间读取数据。
dynamic-datasource
是一个开源的 SpringBoot 多数据源启动器,提供了丰富的功能,使用者只需完成基本的数据源配置,配合使用@DS
注解即可轻松实现多数据源之间的切换。其支持 Jdk 1.7+, SpringBoot 1.5.x 2.x.x 3.x.x。JPA用户不建议使用,JPA自带事务,无法连续切库。
以下特性和约定摘录自官方文档:dynamic-datasource
特性
支持 数据源分组 ,适用于多种场景 纯粹多库 读写分离 一主多从 混合模式。
支持数据库敏感配置信息 加密(可自定义) 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.datasource.dynamic.primary
修改。注:官网文档只有基础篇可免费查阅,其他内容查阅需付费29.9¥
,因此如果基础篇所讲解功能无法满足需求(业务场景比较复杂)且不愿付费请勿使用本框架!
业务说明:从A数据源查询出学生数据同时从B数据源查询出教师数据。
技术选型:SpringBoot 2.7.6 + MyBatis-Plus 3.5.4 + MySQL 8.0
1)引入Maven坐标
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>dynamic-datasource-spring-boot-starter</artifactId>
<version>3.5.2</version>
</dependency>
2)创建模拟数据库表,
# A 数据源
create DATABASE testA;
use testA;
CREATE TABLE student(
id int,
username VARCHAR(12)
);
# B 数据源
create DATABASE testB;
use testB;
CREATE TABLE teacher(
id int,
username VARCHAR(12)
);
3)在yml文件中配置数据源
spring: datasource: dynamic: primary: testA #设置默认的数据源或者数据源组,默认值即为master strict: false #严格匹配数据源,默认false. true未匹配到指定数据源时抛异常,false使用默认数据源 datasource: testA: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/testA username: root password: root testB: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/testB username: root password: root
4)可以用MyBatis-X插件快速生成项目骨架。
5)使用@DS
注解在mapper文件中指定数据源。注意,数据源名称需要与yml配置中的一致。
// 指定学生表的数据源为testA
@DS("testA")
public interface StudentMapper extends BaseMapper<Student> {
}
// 指定教师表的数据源为testB
@DS("testB")
public interface TeacherMapper extends BaseMapper<Teacher> {
}
5)创建测试类进行测试
@SpringBootTest public class MultipleDataSourceTest { @Resource private StudentService studentService; @Resource private TeacherService teacherService; @Test void testSelect() { System.out.println("====== 学生表数据 ======"); for (Student student : studentService.list()) { System.out.println(">>> " + student); } System.out.println("====== 教师表数据 ======"); for (Teacher teacher : teacherService.list()) { System.out.println(">>> " + teacher); } } }
6)相关执行日志查看,可以通过日志看到已经成功加载两个数据源并且指定默认数据源为[testA],同时我们所查询的数据也能正常出来。
INFO 312 --- [main] com.zaxxer.hikari.HikariDataSource: testA - Starting... INFO 312 --- [main] com.zaxxer.hikari.HikariDataSource: testA - Start completed. INFO 312 --- [main] com.zaxxer.hikari.HikariDataSource: testB - Starting... INFO 312 --- [main] com.zaxxer.hikari.HikariDataSource: testB - Start completed. INFO 312 --- [main] c.b.d.d.DynamicRoutingDataSource: dynamic-datasource - add a datasource named [testB] success INFO 312 --- [main] c.b.d.d.DynamicRoutingDataSource: dynamic-datasource - add a datasource named [testA] success INFO 312 --- [main] c.b.d.d.DynamicRoutingDataSource: dynamic-datasource initial loaded [2] datasource,primary datasource named [testA] ====== 学生表数据 ====== >>> Student(id=1, username=学生1) >>> Student(id=2, username=学生2) >>> Student(id=3, username=学生3) >>> Student(id=4, username=学生4) >>> Student(id=5, username=学生5) ====== 教师表数据 ====== >>> Teacher(id=1, username=教师1) >>> Teacher(id=2, username=教师2) >>> Teacher(id=3, username=教师3) >>> Teacher(id=4, username=教师4) >>> Teacher(id=5, username=教师5) INFO 312 --- [ionShutdownHook] c.b.d.d.DynamicRoutingDataSource: dynamic-datasource start closing .... INFO 312 --- [ionShutdownHook] com.zaxxer.hikari.HikariDataSource: testB - Shutdown initiated... INFO 312 --- [ionShutdownHook] com.zaxxer.hikari.HikariDataSource: testB - Shutdown completed. INFO 312 --- [ionShutdownHook] com.zaxxer.hikari.HikariDataSource: testA - Shutdown initiated... INFO 312 --- [ionShutdownHook] com.zaxxer.hikari.HikariDataSource: testA - Shutdown completed. INFO 312 --- [ionShutdownHook] c.b.d.d.DynamicRoutingDataSource: dynamic-datasource all closed success,bye
以上示例可以完成基本的多数据源切换需求,对于一些复杂场景,由于官方文档付费,请根据需要使用。例如:
在需要切换数据源的代码最外层加上了事务注解@Transactional
将会导致数据源切换失效,上述代码加上注解运行将报错(由于无法切换数据源,将使用默认数据源,如果默认数据源中没有对应的表将报错),在网上检索发现通过添加官方提供的@DSTransactional
即可实现事务下数据源切换:
@Test
@Transactional
void testSelect() {
System.out.println("====== 学生表数据 ======");
for (Student student : studentService.list()) {
System.out.println(">>> " + student);
}
System.out.println("====== 教师表数据 ======");
for (Teacher teacher : teacherService.list()) {
System.out.println(">>> " + teacher);
}
}
在多线程情况下,如果使用编码方式实现数据源切换也将导致问题,需要进行一些其他处理。
最后,补充说明想表达的由于官网文档是付费的,不付费的话许多问题只能搜索寻找解决方法比较麻烦,因此,请根据自身业务情况选择使用本框架或其他框架。
原文链接:https://blog.csdn.net/m0_66570338/article/details/140771631
作者:天神下凡
链接:http://www.phpheidong.com/blog/article/554243/59ac405808ac358df8e8/
来源:php黑洞网
任何形式的转载都请注明出处,如有侵权 一经发现 必将追究其法律责任
昵称:
评论内容:(最多支持255个字符)
---无人问津也好,技不如人也罢,你都要试着安静下来,去做自己该做的事,而不是让内心的烦躁、焦虑,坏掉你本来就不多的热情和定力
Copyright © 2018-2021 php黑洞网 All Rights Reserved 版权所有,并保留所有权利。 京ICP备18063182号-4
投诉与举报,广告合作请联系vgs_info@163.com或QQ3083709327
免责声明:网站文章均由用户上传,仅供读者学习交流使用,禁止用做商业用途。若文章涉及色情,反动,侵权等违法信息,请向我们举报,一经核实我们会立即删除!