mybatis-plus加载多个module的mapper踩坑记录

news/2024/10/4 5:36:33

背景

 有一个多模块的项目,每个模块中都有自己的mapper.xml文件。但是在执行一次SQL查询中,mybatis却报出了下面的异常

 

排查过程

第一步,先检查mapper扫描是否正确

 

先找到这个方法的位置

 

可以看到包名是com.pinming.security.responsibility.mapper

 

检查SpringBoot启动类的注解

 

用通配符的方式匹配路径,可以看到这个写法没有任何问题

 

然后我又执行了别的mapper类的查询,发现除了第一个module下的两个mapper的自定义查询方法能够被成功映射,其他mapper的方法都会报出上述异常,可以断定确实是mybatis没有扫描到全部的mapper.xml

 

为了知道是哪里出了问题,我们直接开始debug源码,探究mybatis扫描mapper.xml的原理

 

根据报错的堆栈信息,我们定位到了报错的最终位置

 

代码为什么会进入到这里?

我们先来看这里的判断逻辑:ms == null,且方法上不带Flush这个注解,程序就会进行到我们报错的位置

首先思考,Flush这个注解是什么?不知道,也没用过,而且印象中mapper的方法不需要这个注解也能注册上去,所以问题一定出在ms == null的问题上

那么ms是什么?怎么来的?再往上看,它的类型是MappedStatement,逐词翻译就是“映射的语句”,通过resolveMappedStatement方法得到,那我们将断点加到这里,重新执行代码

 

进入方法内部

 

发现最后因为configuration.hasStatement(statementId) = falsemapperInterface.equals(declaringClass) = true,最后返回了null

后一个判断分支判断的时接口名称是否匹配,这里一定会匹配,前一个判断分支判断是否有这个语句,很显然没找到,那么继续debug进入前一个语句

 

 

这里我debug到buildAllStatements方法里看了半天,发现问题不在这里,就不赘述了

这里我们发现,所有语句被映射在了mappedStatements

 

找到它被赋值的地方,我们就能知道mapper中我们自定义的方法是在哪里被映射的

 

 

它有唯一的put入口,将断点加在这里,我们重启程序,观察映射的过程

 要注意这里要给断点加一个condition,ms.getId()就是方法的全路径,只看自己加的方法是怎么被映射的,因为mybatis-plus的baseMapper有很多内置的方法是通过其他方法初始化的,不要去管那些

 

我们根据这个堆栈列表,一点点往回看

此处省略几十分钟,中间走错了很多路。最终我们找到了这里

 

遍历mapperLocations,解析每一个xml,正常来说mapperLocations肯定会包含每个mapper.xml,那我们看看它有哪些值

 

居然只有meeting这个模块下的两个mapper.xml?为什么?

我们往上找一下这个mapperLocations是怎么来的

 

 

用同样的方法,找到了它唯一被赋值的地方,打下断点,重启程序。感觉离真相越来越近了哈哈哈!

 

进入断点,同样通过左下角的堆栈信息不断往回找

 

这回只往上找了一步就发现了加载它的地方

再把断点打在properties.resolveMapperLocations()这行,重启!

 

下面贴上我debug操作的每一步,红框就是我debug进入的方法体

 

 

 

 这里是什么?一脸懵逼,我先看看最后会进到哪个分支

 

再进去

 

这里看到,spring根据我们配置的mapper.xml路径,开始搜索所有匹配的文件

走到这里不用往下看了,因为这往下的搜索都是根据locationPattern这个入参来决定的,问题一定出在locationPattern

确定了之后,我们再往回一步

 

到这里,我们仔细阅读代码,发现一个关键的词语:all

通过猜测,我们得通过调整locationPattern的值,让代码进入上面的分支,继续往前看看locationPattern是怎么来的

 

在这里,遍历mapperLocations得到下面的入参locationPattern

 

这个mapperLocations是一个成员变量,并且我们发现MybatisPlusProperties这个类是通过配置文件注入的

 

在配置文件中搜索mybatis-plus

 

破案了!就是这个值!

那我们要改成什么值呢?回到前面的判断分支

 

 

可见,我们的配置必须以classpath*:开头

试一试

 

配置完之后重启,执行方法,成功!

结论

想要多个module中的mapper.xml文件都被加载到,配置文件中mybatis-plus.mapper-locations这一项必须以classpath*:开头,否则就只会加载匹配到的第一个module中的指定目录

 

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈,一经查实,立即删除!

相关文章

Quasar+Electron开发打包为桌面端exe

上一篇博客写了 Quasar+Cordova开发打包移动端app ,今天来写一下Quasar+Electron如何开发打包为桌面端exe。 Electron 英文文档:https://www.electronjs.org/docs/latest/ Electron 中文文档:https://electron.nodejs.cn/ Quasar+Electron文档:https://www.quasar-cn.cn/q…

带你走进信息安全软件架构

经纬恒润车端信息安全解决方案整合了 MCU 端以及 MPU 端的信息安全解决方案,具体方案包括 Security Boot、安全通信、安全存储、安全诊断和入侵检测等,能满足欧标强制法规要求和国内信息安全法规要求,符合欧标出口要求的车载信息安全技术架构。 汽车信息安全逐步受到重…

爬虫 | 防盗链和代理

防盗链referer: 一种反爬方式。一些网站在响应之前会先溯源,检查请求的网址X,是从哪个链接进入的(即上一级网址是谁),比如:通过网址A--->进入网址X,那么上一级就是A。如果发现上一级网址不存在,或者错误,则认为是其他歪门邪道来的,就不给你数据。这个就是防盗链r…

【接口自动化测试框架练习】springboot+react+mysql~极简版postman

可以说是一个toy program,chatgpt完成了一部分工作,我也完成了一部分工作,我俩合作的,我占百分之80%,他百分之20%,哈哈没他不行,源码奉上。https://github.com/Jinwenxin/test-api-frontend 1.功能简介: 分成三部分,如左侧导航栏所示:测试用例管理:测试用例的增删改…

django 的安装和启动

1.pycharm创建project 方法与之前selenium相同 2.app的创建和说明 在项目目录下(与manange.py同级的)的地方 打开终端 在项目目录下输入pyhton manage.py startapp app01(这个是你想给app命名的名字),这样就创建好了app。然后注册app01,找到jango里的settings文件,在INST…

【VMware vSAN】修改虚拟机名称后如何改变在 vSAN 数据存储中的名称。

如果在 vSphere 集群环境修改虚拟机的名字后,虚拟机所在的数据存储文件中的名称并不会改变,我们知道可以通过执行一下 Storage vMotion 操作,以通知虚拟机在数据存储中的改变。但是,这个操作需要环境中至少具有第二个数据存储才能执行 Storage vMotion 来往返迁移虚拟机,最…

go的深拷贝跟浅拷贝

Golang面试官:聊一聊浅拷贝和深拷贝 原创 吃个大西瓜 Coding Big Tree 2024-06-09 08:01 北京 听全文浅拷贝和深拷贝浅拷贝后的对象和源对象是同一个对象,值被修改,原值的数据也会被修改 深拷贝后的对象,是一个全新的对象,和源对象没有关系,修改值不会相互影响浅拷贝示例…

LLM应用实战:当图谱问答(KBQA)集成大模型(三)

本文主要是针对KBQA方案基于LLM实现存在的问题进行优化,主要涉及到响应时间提升优化以及多轮对话效果优化,提供了具体的优化方案以及相应的prompt。1. 背景 最近比较忙(也有点茫),本qiang~想切入多模态大模型领域,所以一直在潜心研读中... 本次的更新内容主要是响应图谱问答…