SpringBoot3.0整合Mybatis-plus实现多数据源(重构类方式)

news/2025/3/12 23:48:35/文章来源:https://www.cnblogs.com/Mr-Sponge/p/18516306

背景

前段时间在做一个数据中台的项目,系统用到了不同数据库中的数据。自己又不想手写JDBC连接,既然我有这个需求,那功能应该有人实现了,于是开始了网上搜了,搜索后发现基本都是讲读写分离、主备切换的,后面也查略了Mybatis-plus的官网,里面有这个功能,但好像是我组件的版本之间不兼容,导致出现了一些奇怪的bug,比如:Property ‘sqlSessionFactory‘ or ‘sqlSessionTemplate‘ are required或者是无法访问javax.servlet.http.HttpServlet 亦或者是Cannot resolve reference to bean ‘sqlSessionFactory‘ while setting constructor argument; nested exce

总之,历经多重磨难总算是解决了

选择合适的组件版本能事半功倍

组件版本

SpringBoot:3.0.0

JDK:19

MySQL:8.0.28

ClickHouse:21.4.6

clickhouse-jdbc:0.3.2-patch11

Mybatis-plus:3.5.7

dynamic-datasource:3.3.2

Druid:1.2.20

具体的pom.xml文件如下:

	<parent><artifactId>spring-boot-starter-parent</artifactId><groupId>org.springframework.boot</groupId><!--springboot3 开始,JDK最低要求要11,该项目用的是19--><version>3.0.0</version></parent><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId></dependency>
<!--        mysql-jdbc 驱动--><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.28</version></dependency>
<!--        clickhouse-jdbc 驱动--><dependency><groupId>com.clickhouse</groupId><artifactId>clickhouse-jdbc</artifactId><version>0.3.2-patch11</version><classifier>all</classifier><exclusions><exclusion><groupId>*</groupId><artifactId>*</artifactId></exclusion></exclusions></dependency>
<!--json web token--><dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt-api</artifactId><version>0.11.5</version></dependency><dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt-impl</artifactId><version>0.11.5</version></dependency><dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt-jackson</artifactId><version>0.11.5</version></dependency><!-- lombok 依赖 --><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency><!-- mybatis-plus 依赖 --><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.5.7</version></dependency><!-- 动态配置多种数据源 --><dependency><groupId>com.baomidou</groupId><artifactId>dynamic-datasource-spring-boot-starter</artifactId><version>3.3.2</version></dependency><!-- druid启动器的依赖  --><dependency><groupId>com.alibaba</groupId><artifactId>druid-spring-boot-3-starter</artifactId><version>1.2.20</version></dependency></dependencies>

至于为什么选择这些版本的组件,我也不知道🤐干活就是了。

需求

在同一个(Maven)项目中,根据不同请求,实现对不同数据库的操作,数据源选择Druid。

源码

项目代码整体架构

application.yml配置文件

spring:datasource:dynamic:primary: systemstrict: falsedatasource:system:url: jdbc:mysql://xxx.xxx.xxx.xxx:xxxx/zhongtai_admin?useSSL=false&useUnicode=true&characterEncoding=utf8&serverTimezone=UTCusername: xxxxpassword: xxxxdriver-class-name: com.mysql.cj.jdbc.Drivertype: com.alibaba.druid.pool.DruidDataSourceinitialSize: 5minIdle: 5maxActive: 20maxWait: 600000stat-view-servlet:enabled: trueurl-pattern: /druid/*timeBetweenEvictionRunsMillis: 600000minEvictableIdleTimeMillis: 300000validationQuery: SELECT 1testWhileIdle: truetestOnBorrow: falsetestOnReturn: falsepoolPreparedStatements: truefilters: stat,wallmaxPoolPreparedStatementPerConnectionSize: 20useGlobalDataSourceStat: trueconnectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500report:url: jdbc:clickhouse://xxx.xxx.xxx.xxx:xxxx/adsenabled: truedriver-class-name: com.clickhouse.jdbc.ClickHouseDrivertype: com.alibaba.druid.pool.DruidDataSourceinitialSize: 5minIdle: 5maxActive: 20maxWait: 600000stat-view-servlet:enabled: trueurl-pattern: /druid/*timeBetweenEvictionRunsMillis: 600000minEvictableIdleTimeMillis: 300000validationQuery: SELECT 1testWhileIdle: truetestOnBorrow: falsetestOnReturn: falsepoolPreparedStatements: truefilters: stat,wallmaxPoolPreparedStatementPerConnectionSize: 20useGlobalDataSourceStat: trueconnectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500

重写相关容器类

不知道大家是否还了解 SpringBoot 的自动装配原理(过程),像我们直接导 mybatis-plus-boot-starter 或是其他依赖,只要版本之间没问题,理论上是不会直接报:Property ‘sqlSessionFactory‘ or ‘sqlSessionTemplate‘ are required这些错误的,mybatis-plus 里是已经自动封装好了的。

ps:这个错误是我加了 dynamic-datasource-spring-boot-starter 后才报的,当时官网介绍很少(版本号什么的都没给),给了一个详细了解连接,跳转后要付费查略😡

遇到这些问题怎么办?只能自己重写相关方法,注入到bean中了。

SystemDataSourceConfig.java

ackage com.pzb.admin.config;import com.alibaba.druid.pool.DruidDataSource;
import com.baomidou.mybatisplus.core.MybatisConfiguration;
import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean;
import org.apache.ibatis.logging.stdout.StdOutImpl;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;import javax.sql.DataSource;
import java.sql.SQLException;/*** @Description TODO 因为涉及多个数据源,现重写sqlSessionFactory等配置类,根据不同的mapper.xml映射文件,操作不同的数据源* @Author zbpeng* @DATE 2024/10/29 10:51*/
@Configuration
@MapperScan(basePackages = "com.pzb.*.mapper", sqlSessionFactoryRef = "sqlSessionFactory")
public class SystemDataSourceConfig {@Bean(name = "dataSource")@ConfigurationProperties(prefix = "spring.datasource.dynamic.datasource.system")@Primarypublic DataSource dataSource() throws SQLException {// 选择Druid 数据源DruidDataSource druidDataSource = new DruidDataSource();druidDataSource.setFilters("stat");return druidDataSource;}@Bean(name = "sqlSessionFactory")@Primarypublic SqlSessionFactory sqlSessionFactory(@Qualifier("dataSource") DataSource dataSource) throws Exception {MybatisSqlSessionFactoryBean bean = new MybatisSqlSessionFactoryBean();bean.setDataSource(dataSource);bean.setTypeAliasesPackage("com.pzb.*.bean");bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:mappers/system/*.xml"));//其他配置 ps:sqlSessionFactoryBean内可以配置yml的一切配置MybatisConfiguration mybatisConfiguration = new MybatisConfiguration();//是否下划线转驼峰mybatisConfiguration.setMapUnderscoreToCamelCase(true);//设置日志mybatisConfiguration.setLogImpl(StdOutImpl.class);bean.setConfiguration(mybatisConfiguration);return bean.getObject();}@Bean(name = "transactionManager")@Primarypublic DataSourceTransactionManager transactionManager(@Qualifier("dataSource") DataSource dataSource) {return new DataSourceTransactionManager(dataSource);}@Bean(name = "sqlSessionTemplate")@Primarypublic SqlSessionTemplate sqlSessionTemplate(@Qualifier("sqlSessionFactory") SqlSessionFactory sqlSessionFactory) {return new SqlSessionTemplate(sqlSessionFactory);}
}

ReportDataSourceConfig.java

package com.pzb.statistic.config;import com.alibaba.druid.pool.DruidDataSource;
import com.baomidou.mybatisplus.core.MybatisConfiguration;
import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean;
import org.apache.ibatis.logging.stdout.StdOutImpl;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;import javax.sql.DataSource;
import java.sql.SQLException;/*** @Description TODO 因为涉及多个数据源,现重写sqlSessionFactory等配置类,根据不同的mapper.xml映射文件,操作不同的数据源* @Author zbpeng* @DATE 2024/10/29 10:55*/
@Configuration
@MapperScan(basePackages = "com.pzb.statistic.mapper", sqlSessionFactoryRef = "sqlSessionFactory2")
public class ReportDataSourceConfig {@Bean(name = "dataSource2")@ConfigurationProperties(prefix = "spring.datasource.dynamic.datasource.report")public DataSource dataSource() throws SQLException {DruidDataSource druidDataSource = new DruidDataSource();druidDataSource.setFilters("stat");return druidDataSource;}@Bean(name = "sqlSessionFactory2")public SqlSessionFactory sqlSessionFactory(@Qualifier("dataSource2") DataSource dataSource) throws Exception {MybatisSqlSessionFactoryBean bean = new MybatisSqlSessionFactoryBean();bean.setDataSource(dataSource);bean.setTypeAliasesPackage("com.pzb.report.bean");bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:mappers/report/*.xml"));//其他配置 ps:sqlSessionFactoryBean内可以配置yml的一切配置MybatisConfiguration mybatisConfiguration = new MybatisConfiguration();//是否下划线转驼峰mybatisConfiguration.setMapUnderscoreToCamelCase(true);//设置日志mybatisConfiguration.setLogImpl(StdOutImpl.class);bean.setConfiguration(mybatisConfiguration);return bean.getObject();}@Bean(name = "transactionManager2")public DataSourceTransactionManager transactionManager(@Qualifier("dataSource2") DataSource dataSource) {return new DataSourceTransactionManager(dataSource);}@Bean(name = "sqlSessionTemplate2")public SqlSessionTemplate sqlSessionTemplate(@Qualifier("sqlSessionFactory2") SqlSessionFactory sqlSessionFactory) {return new SqlSessionTemplate(sqlSessionFactory);}
}

​ 后面就正常写就行了,根据你调的Mapper接口方法,找到对应的.xml映射文件,.xml映射文件绑定了不同的JDBC连接器,进而操作不同的数据库。(大概)

参考资料:

https://blog.csdn.net/weixin_42675423/article/details/126932977

https://www.cnblogs.com/gudian/p/15163126.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/824253.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

58. 区间和

题目 本人一开始是这样写的: #include <iostream>using namespace std;const int N = 100010; int n; int s[N];int main() {cin >> n;for (int i = 1; i <= n; i ++ ){int x;cin >> x;s[i] = s[i - 1] + x;}int l = 0, r = 0;while (cin >> l &am…

cin和scanf的返回值知多少

cin的返回值 在 C++ 中,cin 是用于从标准输入(通常是键盘)读取数据的对象。 cin 的返回值实际上是一个流对象(std::istream 类型),可以通过流的状态来检查输入操作是否成功。 以下是一些关于 cin 返回值的关键点:输入成功与失败: 当你使用 cin 进行输入时,可以通过 ci…

多语言 AI 翻译 API 数据接口

多语言 AI 翻译 API 数据接口 ai / 翻译 基于 AI 多语言模型 支持多语言 / 基于模型。1. 产品功能基于自有专业模型进行 AI 多语言翻译 高效的文本翻译性能 全接口支持 HTTPS(TLS v1.0 / v1.1 / v1.2 / v1.3); 全面兼容 Apple ATS; 全国多节点 CDN 部署; 接口极速响应,多…

个人可识别信息(PII) AI 去除 API 数据接口

个人可识别信息(PII) AI 去除 API 数据接口 ai / 隐私保护 基于 AI 模型自动去除个人识别信息(PII) 个人信息保护 / AI 模型 。1. 产品功能基于自有专业模型进行 PII 自动去除 高效处理敏感信息 全接口支持 HTTPS(TLS v1.0 / v1.1 / v1.2 / v1.3); 全面兼容 Apple ATS; 全…

MBR20100CT-ASEMI半塑封肖特基二极管MBR20100CT

MBR20100CT-ASEMI半塑封肖特基二极管MBR20100CT编辑:ll MBR20100CT-ASEMI半塑封肖特基二极管MBR20100CT 型号:MBR20100CT 品牌:ASEMI 封装:TO-220 安装方式:插件 批号:最新 最大平均正向电流(IF):20A 最大循环峰值反向电压(VRRM):100V 最大正向电压(VF):0.70V~0…

第三十讲:误删数据后除了跑路,还能怎么办?

第三十讲:误删数据后除了跑路,还能怎么办? 简概还是平淡的开头 ​ 今天我要和你讨论的是一个沉重的话题:误删数据。 ​ 在前面几篇文章中,我们介绍了 MySQL 的高可用架构。 ​ 当然,传统的高可用架构是不能预防误删数据的,因为主库的一个 drop table 命令,会通过 binlo…

TYPE-C PD浅谈(一)

聊聊USB Power Delivery两三事,接下来会依下列几个主题来探讨What is Power Delivery E-Marker Attached Source CAP Sink CAP Power Role Swap Data Role Swap VCONN Swap Alternate Mode Charger Design Note What is Power DeliveryUSB界面历经20年的演变,在界面上一直没有…

【semantic Kernel】对接 Ollama

在 chatGPT 的推动下。LLM 简直火出天际,各行各业都在蹭。听说最近 meta 开源的 llama3 模型可以轻松在普通 PC 上运行,这让我也忍不住来蹭一层。以下是使用 ollama 试玩 llama3 的一些记录。 什么是 llama LLaMA(Large Language Model Meta AI)是Meta开发的大规模预训练语…

Kafka的消费者

Kafka的消费者 Kafka采用消费者组的方式来消费消息,一个消费者组中可以包含多个消费者。消费者对象订阅主题并接收Kafka的消息,然后验证消息并保存结果。尽管一个消费者组中可以包含多个消费者,但是它们订阅的都是同一个主题的消息。 1. 消费模式 当生产者将消息发送到Kafka…

GIS空间索引技术

地理信息系统(Geography Information System,简称GIS)的主要任务之一是有效地检索空间数据及快速响应不同用户的在线查询。地理空间索引技术和方法是GIS的关键技术。是快速高效查询、检索和显示地理空间数据的重要指标。 常用的空间索引技术介绍和比较: 网格空间索引、四叉树…

Base64编码原理

Base64编码原理 Base64作用 目前Base64已经成为网络上常见的传输8Bit字节代码的编码方式之一。在做支付系统时,系统之间的报文交互都需要使用Base64对明文进行转码,然后再进行签名或加密,之后再进行(或再次Base64)传输。 Base64编码原理 Base64的原理比较简单,每当我们使…

项目管理平台实操:项目经理如何快速生成项目报告?(3分钟教程)

一、项目管理平台与报告生成的关联 项目管理平台在项目管理中起着至关重要的作用。它为项目经理提供了一个集中化的管理工具,能够有效地组织和协调项目的各个方面。 首先,项目管理平台可以实现对项目任务的全面管理。通过任务清单功能,项目经理可以清晰地了解每个任务的名称…