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

背景

 有一个多模块的项目,每个模块中都有自己的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中的指定目录

 

posted @ 2024-06-12 13:22  蓝瓶的真好喝  阅读(561)  评论(1编辑  收藏  举报