SpringBoot项目多数据源配置与MyBatis拦截器生效问题解析

在日常项目开发中,由于某些原因,一个服务的数据源可能来自不同的库,比如:

  1. 对接提供的中间库,需要查询需要的数据
  2. 同步数据,需要将一个库的数据同步到另一个库,做为同步工具的服务
  3. 对接第三方系统,由于时间等原因不方便提供接口,开放数据库提供一些查询视图

在实际项目中,多数据源的配置是常见需求。本博客将详细介绍如何在Spring Boot项目中配置多个数据源,并使用MyBatis进行整合。同时,我们将解决在多数据源配置下自定义拦截器不生效的问题。

1、配置多数据源方式

我所在项目使用的SpringBoot+Mybatis,首先需要添加不同数据源的配置,一般为了区分数据源,会是在单数据源的基础上再datasource节点和具体配置节点之间自定义数据源的名称,比如default表示默认数据源。

spring:thymeleaf:cache: falsedatasource:# 默认数据源配置default:name: dataSourceurl: jdbc:log4jdbc:Postgresql://ip:port/db?currentSchema=db&ApplicationName=testusername: ENCRYPT#wwWQEj+qg=password: ENCRYPT#Jb0N1GHFwD+MWQRiSfHg==driver-class-name: net.sf.log4jdbc.sql.jdbcapi.DriverSpytype: com.alibaba.druid.pool.DruidDataSourcedruid:validation-query: select 1min-idle: 20initial-size: 20max-active: 50# 第二数据源secondary:name: dataSourceurl: jdbc:log4jdbc:Postgresql://ip:port/db?currentSchema=db&ApplicationName=testusername: ENCRYPT#qdTt8x5ss=password: ENCRYPT#YvZIPJii8D+MWQRiSfHg==driver-class-name: net.sf.log4jdbc.sql.jdbcapi.DriverSpytype: com.alibaba.druid.pool.DruidDataSourcedruid:validation-query: select 1min-idle: 20initial-size: 20max-active: 50

因为有了多个数据源,需要手动配置创建数据源实例, 默认数据源添加@Primary注解进行标注。

@Configuration
public class DataSourceConfig {
​/*** 构建主数据源* @return 数据源对象*/@Primary@Bean(name = "defaultDataSource")@ConfigurationProperties(prefix = "spring.datasource.default")public DataSource defaultDataSource() {DruidDataSource dataSource = new DruidDataSource();return dataSource;}
​/*** 第二数据源* @return 数据源对象*/@Bean(name = "secondaryDataSource")@ConfigurationProperties(prefix = "spring.datasource.secondary")public DataSource secondaryDataSource() {return new DruidDataSource();}
}

2、Mybatis配置

使用单数据源时,Mapper文件的扫描一般是在启动类上使用@MapperScan配置扫描路径的,但是多数据源则需要进行区分,扫描不同的路径;

SqlSessionFactory 在 MyBatis 中充当着重要的角色,它通过将配置信息加载到内存中,创建和管理 SqlSession 实例,以及配置和创建 Mapper 对象,为开发者提供了便捷的数据库操作接口。通常情况下,一个应用程序只需要创建一个 SqlSessionFactory 实例,并在整个应用程序的生命周期中共享该实例。多数据源场景下,不同的数据源也需要创建自己的SqlSessionFactory 实例。

@MapperScan(basePackages = {"com.xx.xx.*.mapper", "com.xx.xx.**.mapper","com.xx.xx.report.provider.report.db"},sqlSessionFactoryRef = "defaultSqlSessionFactory", sqlSessionTemplateRef = "defaultSqlSessionTemplate")
@Configuration
public class DefaultMybatisConfig {
​@Autowired@Qualifier("dataSource")private DataSource defaultDataSource;
​@Resourceprivate DictGroupTagInterceptor dictGroupTagInterceptor;
​@Resourceprivate PageInterceptor pageInterceptor;
​@Resourceprivate DefaultMybatisInterceptor defaultMyBatisInterceptor;
​@Bean(name = "defaultTransactionManager")@Primarypublic DataSourceTransactionManager defaultTransactionManager() {return new DataSourceTransactionManager(defaultDataSource);}
​@Primary@Bean(name = "defaultSqlSessionFactory")public SqlSessionFactory defaultSqlSessionFactory() throws Exception {final SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();sessionFactory.setDataSource(defaultDataSource);// Artery的分页插件,数据字典插件(用于动态替换模式名称)sessionFactory.setPlugins(pageInterceptor, dictGroupTagInterceptor, defaultMyBatisInterceptor);return sessionFactory.getObject();}
​
​@Bean(name = "defaultSqlSessionTemplate")public SqlSessionTemplate defaultSqlSessionTemplate(@Qualifier("defaultSqlSessionFactory") SqlSessionFactory sqlSessionFactory) {return new SqlSessionTemplate(sqlSessionFactory);}
}

对于其他数据源的Mybatis配置也是一样,创建配置类进行配置即可

3、过程中遇到的问题

服务正常启动,对应数据源的访问也没有问题;一个业务场景需要用到业务表的创建时间,创建时间为null导致系统异常。

排查发现,业务表最近的业务数据的创建人,创建时间,修改人,修改时间字段值都是空的。

这些基础字段并不是通过业务数据的创建和修改赋值的,都是实现Mybatis的拦截器Interceptor进行实现的,说明拦截器并未生效。

判断当前操作是新增或者修改,根据当前登录人信息对基础字段赋值

@Override
public Object intercept(Invocation invocation) throws Throwable {
​Object[] args = invocation.getArgs();IUser currentUser = securityService.getCurrUserInfo();if(Objects.isNull(currentUser)){log.warn("没有登录的用户在操作数据库,请关注,参数:{},线程:{}",args,Thread.currentThread().getName());currentUser = new User();currentUser.setCorpId("unkown");currentUser.setId("unkown");}if (args.length > 1) {MappedStatement ms = (MappedStatement)args[0];try {if (SqlCommandType.INSERT.equals(ms.getSqlCommandType())) {preInsert(args[1], currentUser);} else if (SqlCommandType.UPDATE.equals(ms.getSqlCommandType())) {preUpdate(args[1], currentUser);}} catch (Exception e) {log.warn("intercept exception : " + e.getMessage(), e);}}
​return invocation.proceed();
}

1、那么系统单数据源时,自定义的拦截器是如何生效的呢?

原因就在于MybatisAutoConfiguration类 ,作用是自动配置 MyBatis 相关的组件,包括创建SqlSessionFactoryMybatisAutoConfiguration实现了InitializingBean进行初始化操作,在实例化时注入了Interceptor对象。

通过跟踪代码发现,SqlSessionFactory会在MybatisAutoConfiguration创建中创建实例,而这些自定义的拦截器会在创建SqlSessionFactory实例的时候进行设置。

其中注解@ConditionalOnMissingBean表示容器中不存在某个指定类型或名称的 Bean 时,才会生效。所以在SqlSessionFactory已经存在的实例情况之下并不会创建实例,也就解释了我们配置多数据源情况下自定义拦截器不生效的原因。

所以解决办法就很简单了,在我们自定义的Mybatis配置类中注入自定义的拦截器,设置到SqlSessionFactory当中;

 

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

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

相关文章

肺癌相关文献6

第十四篇 Classification of lung adenocarcinoma based on stemness scores in bulk and single cell transcriptomes IF:6.0 中科院分区:2区 生物学WOS分区:Q1被引次数: 4 背景:癌细胞具有无限期自我更新和增殖的能力[2]。在一…

JavaScript进阶:WebAPIs重点知识整理1

目录 1 DOM修改元素内容 2 DOM修改元素常见属性 3 修改元素样式属性 3.1 通过style修改元素样式 3.2 通过类名className修改元素样式 3.3 通过classList修改元素样式 4 操作表单元素属性 5 自定义属性 6 定时器 7 事件监听 7.1 点击事件 click 7.2 鼠mouseenter和移…

Laya3.0 相机使用

摄像机,是3D场景里边最经常使用的对象了。 官方文档:点击这里学习 1.投影 Projection 透视: 模拟人眼的视觉效果,近大远小。模拟物理世界的规律,将眼睛或相机抽象成一个点,此时视锥体内的物体投影到视平…

YOLO 自己训练一个模型

一、准备数据集 我的版本是yolov8 8.11 这个目录结构很重要 ultralytics-main | datasets|coco|train|val 二、训练 编写yaml 文件 # Train/val/test sets as 1) dir: path/to/imgs, 2) file: path/to/imgs.txt, or 3) list: [path/to/imgs1, path/to/imgs2, ..] path…

Java项目:基于SSM框架实现同城蔬菜配送管理系统(SSM+B/S架构+源码+数据库+毕业论文)

一、项目简介 本项目是一套ssm825基于SSM框架实现同城蔬菜配送管理系统,主要针对计算机相关专业的正在做毕设的学生与需要项目实战练习的Java学习者。 包含:项目源码、数据库脚本等,该项目附带全部源码可作为毕设使用。 项目都经过严格调试&…

【Web前端开发基础】CSS3之空间转换和动画

CSS3之空间转换和动画 目录 CSS3之空间转换和动画一、空间转换1.1 概述1.2 3D转换常用的属性1.3 3D转换:translate3d(位移)1.4 3D转换:perspective(视角)1.5 3D转换:rotate3d(旋转&a…

集美大学“第15届蓝桥杯大赛(软件类)“校内选拔赛 D矩阵选数

经典的状态压缩DP int dp[15][(1<<14)10]; int a[15][15]; void solve() {//dp[i][st]考虑到了第i行 并且当前考虑完第i行以后的选择状态是st的所有方案中的最大值for(int i1;i<13;i)for(int j1;j<13;j)cin>>a[i][j];for(int i1;i<13;i){for(int j0;j<…

Web网页生成桌面应用

前言&#xff1a;网页生成桌面指的是将一个网页保存为桌面应用程序的形式&#xff0c;使得用户可以在桌面上直接打开该网页&#xff0c;而不必通过浏览器打开。这种桌面应用程序一般具有独立的窗口、菜单、工具栏等界面元素&#xff0c;能够提供更加方便快捷的使用体验。 实现…

宠物互联网医院系统

在数字时代&#xff0c;宠物医疗迎来了一场革新&#xff0c;动物互联网医院系统以其先进的技术和智能的特性成为宠物护理的领军者。本文将介绍宠物互联网医院系统的一些关键技术和代码示例&#xff0c;揭示这一科技奇迹的实现原理。 1. 远程医疗服务的实现 远程医疗服务是宠…

谷粒商城配置虚拟机

一、创建虚拟机 之前有在VM里面建一个ubuntu的虚拟机&#xff0c;准备拿来直接用&#xff0c;网络设置为NAT模式&#xff0c;查看我的虚拟机是虚拟机&#xff1a;192.168.248.128 主机&#xff1a; 192.168.2.12。可以互相ping通。 二、linux安装docker Docker docker是虚拟…

无人机航迹规划(六):七种元启发算法(DBO、LO、SWO、COA、LSO、KOA、GRO)求解无人机路径规划(提供MATLAB代码)

一、七种算法&#xff08;DBO、LO、SWO、COA、LSO、KOA、GRO&#xff09;简介 1、蜣螂优化算法DBO 蜣螂优化算法&#xff08;Dung beetle optimizer&#xff0c;DBO&#xff09;由Jiankai Xue和Bo Shen于2022年提出&#xff0c;该算法主要受蜣螂的滚球、跳舞、觅食、偷窃和繁…

【医学图像数据增强】切割-拼接(CS-DA)

切割-拼接CS-DA CS-DA 核心思想自然图像和医学图像之间的关键差异CS-DA 步骤确定增强后的数据数量 代码复现 CS-DA 核心思想 论文链接&#xff1a;https://arxiv.org/ftp/arxiv/papers/2210/2210.09099.pdf 大多数用于医学分割的数据增强技术最初是在自然图像上开发的&#x…

Spring Cloud 系列:基于Seata 实现 XA模式

https://seata.io/zh-cn/docs/user/mode/xa https://seata.io/zh-cn/docs/dev/mode/xa-mode XA 规范 是 X/Open 组织定义的分布式事务处理&#xff08;DTP&#xff0c;Distributed Transaction Processing&#xff09;标准&#xff0c;XA 规范 描述了全局的TM与局部的RM之间的…

C++入门学习(十五)运算符

算术运算符&#xff1a;用于处理四则运算赋值运算符&#xff1a;用于将表达式的值赋给变量比较运算符&#xff1a;用于表达式的比较&#xff0c;并返回一个真值或假值逻辑运算符&#xff1a;用于根据表达式的值返回真值或假值 一、加减乘除 #include <iostream> #incl…

Simulink|光伏并网逆变器低电压穿越仿真模型

目录 主要内容 模型研究 1.模型总览 2.boost模块 3.Inverter模块 4.控制模块 5.信号模块 结果一览 下载链接 主要内容 该模型为光伏逆变器低电压穿越仿真模型&#xff0c;采用boost加NPC拓扑结构&#xff0c;基于MATLAB/Simulink建模仿真。模型具备中点平衡…

【AI视野·今日Robot 机器人论文速览 第七十五期】Thu, 11 Jan 2024

AI视野今日CS.Robotics 机器人学论文速览 Thu, 11 Jan 2024 Totally 16 papers &#x1f449;上期速览✈更多精彩请移步主页 Daily Robotics Papers Analytical Model and Experimental Testing of the SoftFoot: an Adaptive Robot Foot for Walking over Obstacles and Irre…

解决Windows下Goland的Terminal设置为Git Bash失败

路径不要选错了&#xff1a; 如果还是不行&#xff1a; 把bash路径加进去试试 goland设置Terminal

解决方案 | 基于SFTP协议的文件传输断点续传Java实现方案

背景 因项目需要&#xff0c;我们服务每天都需要通过SFTP协议来对接上下游进行文件传输&#xff0c;但是对于一些大文件&#xff0c;在与第三方公司的服务器对接过程中很可能会因为网络问题或上下游服务器性能问题导致文件上传或者下载被中断&#xff0c;每次重试都需要重新对…

《WebKit 技术内幕》学习之五(1): HTML解释器和DOM 模型

第五章 HTML 解释器和 DOM 模型 1.DOM 模型 1.1 DOM标准 DOM &#xff08;Document Object Model&#xff09;的全称是文档对象模型&#xff0c;它可以以一种独立于平台和语言的方式访问和修改一个文档的内容和结构。这里的文档可以是 HTML 文档、XML 文档或者 XHTML 文档。D…

C#hybridCLR热更新方案初探

前言 暂时处于初步研究状态&#xff0c;目前的框架使用还是尚少&#xff0c;本篇文章旨在同步给大家大概的使用流程和使用心得&#xff0c;在初步建立新项目时可以适当考虑。 介绍 热更新 与强制更新相对应&#xff0c;移动平台上App的可执行程序没有发生变化&#xff0c;仅…