如何去寻找解决bug?(以Mapped Statements collection does not contain value for xxx的异常为例)

引言

众所周知,我们完成一个项目的时间三分之一是用来写代码的,而剩下三分之二的时间是用来调试寻找解决bug的。

那么如果能提高解决bug的效率就能大大加快项目的开发速度。

下面我以mybatis框架报的Mapped Statements collection does not contain value for xxx的异常为例,来说说如何有目的,有效率地解决框架。

环境:mysql+mybatis框架+java编写的maven项目

想看具体项目的可以去看我项目实战专栏里的图书信息管理系统(一个适合刚入行新手的练手项目)

链接:https://blog.****.net/qq_46101869/article/details/106910497

案例

好了回归正题,
如何去寻找解决bug?(以Mapped Statements collection does not contain value for xxx的异常为例)

上图是我在调试遇到的一个问题,可以看到程序报了Mapped Statements collection does not contain value for xxx的异常,这很明显是mybatis框架报的异常,通过报错信息大概猜测是mybatis XXX容器内不包含我写的Mapper(因为那时候我还不知道Mapped Statement是什么东西),然后我就无脑将这段报错信息贴到百度上搜,确实有很多博客记录了此错误及解决方法,我截了一个下来,如图:

如何去寻找解决bug?(以Mapped Statements collection does not contain value for xxx的异常为例)

但实际上我按照博客上一个个去做,并没有解决问题,这时候我已经花了一个下午时间去查找,问题没解决,倒是把mybatis框架复习了一遍。

苦思之下,我开始逐步调试,以下是我的思考过程:

因为问题肯定出在mybatis框架上,所以我逐步调试,但是呢,我又不懂mybatis源码,看得云里雾里。不过我之前自学Java的时候,跟着视频写过一个类似mybatis的框架------SORM框架(不过功能肯定没mybatis框架复杂,是个小型版的框架),做完后学了其他知识后,自己又回头帮它迭代优化了一下,增加了新的功能,优化了结构。

如何去寻找解决bug?(以Mapped Statements collection does not contain value for xxx的异常为例)

这段经历让我能大概理解mybatis框架的一些行为,比如在这个地方我就注意到了mappedStatement对象size为0。这时我就猜测这应该是框架本身并没有读取到我写的sql语句,那是由什么造成的呢?

如何去寻找解决bug?(以Mapped Statements collection does not contain value for xxx的异常为例)

这时候我就开始测试,不用接口类的方式(因为创建实体类也是mybatis框架底层做的),为了缩小问题的范围,我们采用原始的方式(但不是原生jdbc),发现还是这个错误,然后我开始怀疑mapper注册问题

如何去寻找解决bug?(以Mapped Statements collection does not contain value for xxx的异常为例)

这里我原本是采用包扫描的方式注册,然后我开始尝试用指定路径文件方式去注册

如何去寻找解决bug?(以Mapped Statements collection does not contain value for xxx的异常为例)

然后异常变了,说找不到这个文件

好家伙,之前包扫描的时候报的是Mapped Statements collection does not contain value for xxx,现在直接报没找到这个文件!

这时候我就开始思考为什么?

为什么我用包扫描的方式就不报错呢?而用具体的文件路径就报错呢?

真的是包扫描时找到了xml文件而具体文件路径没找到吗?

不对,不是这样的,换个角度讲,包扫描没扫描到,会报错吗?不会,那问题区间缩小,很可能就是因为xml文件路径的问题。而其他配置文件是找到了的,不然它根本不会提示找不到(路径是写在mybatis-config.xml文件里的),既然我们确定了问题所在,这时候我们就需要尝试改变路径

如何去寻找解决bug?(以Mapped Statements collection does not contain value for xxx的异常为例)

这时候我再去查博客,搜索的不是异常信息,而是配置文件的路径该怎么写?

在搜索的过程中我逐渐意识到我的项目结构可能与别人不同,所以我在搜索时加了Maven限定词,好家伙,不搜不知道,一搜我找到了原因所在。

原来Maven项目编译时会把文件全都输出到Target文件夹下面

如何去寻找解决bug?(以Mapped Statements collection does not contain value for xxx的异常为例)

而默认情况下配置文件只会把resource文件夹下面的配置文件输出,这就造成Java文件夹下面的Mapper文件根本不会输出到target里,这样当然就找不到了,于是我修改了Maven项目中核心配置文件pom.xml信息,加入了下面的配置

如何去寻找解决bug?(以Mapped Statements collection does not contain value for xxx的异常为例)

然后呢?

还是找不到…

本着不抛弃不放弃的精神,我开始关注target文件夹的文件结构

如何去寻找解决bug?(以Mapped Statements collection does not contain value for xxx的异常为例)

什么,居然有两个com.dreamchser,这是为什么呢?

然后我开始测试加百度,然后发现了IDEA的神坑之处------当我们创建一个包时,com.dreamchser和com/dreamchaser是不同的!

com.dreamchaser就是指第二个圈里的包,com/dreamchaser指的是第一个圈里的包

.和/的差别真的是坑死我我了!

我仔细思考了下,之前查询博客的时候,确实有博客提到idea中创建包时/和.是不一样,但当时我以为我的mapper是被读取进去了,所以没在意,只是检查了其他部分,知道后面调试运行底层源码时MappedStatement这个对象的size=0,通过字面意思猜测mybatis实际上是没有读取进去的,进而开始了这方面的排查,最终找到了原因。

如何去寻找解决bug?(以Mapped Statements collection does not contain value for xxx的异常为例)

如果用使用动态代理改造CRUD的方式,用接口实现,这意味着接口路径要和xml中那么namespace中的值一致,而在mybatis配置中mapper注册的时候路径要写的是被打包进target/classes下的路径,注意.和/ 的区别

如何去寻找解决bug?(以Mapped Statements collection does not contain value for xxx的异常为例)

总结

当我们遇到一个bug的时候,不要二话不说就把异常信息Ctrl+C,Ctrl+V去百度。这确实可能会让你解决问题,但是有很大几率是你搜遍了网上的解决方式也没有解决,因为通常一个框架的同一个异常其实是有很多原因,你就会像无头苍蝇那样乱转,运气好可能会解决问题,运气不好就会到处碰壁。虽说面向百度编程这句话不假,但是我们更要做的是知道问题出在哪里。

我们遇到bug,遇到异常所需做的第一件事就是思考为什么会报错,去定位问题的所在。

而在如何定位问题呢?这需要你对程序,对这个框架的运行原理有一定的了解,有对判断问题的直觉和思维。

当然我们也可以利用一些技巧,比如看报错的信息(看不懂英文就网上翻译),根据报错信息来猜测问题的原因;还有就是切换思维,我们应该以程序的思维去思考,如果要这么做程序会怎么做?它需要什么条件?什么情况下回报这种错误?当然其实更有效更简单粗暴的做法就是调试,你可以看看它在那个地方停下报错了,看看调试过程中配置是否加载完全了。

然后我们再有目的地去百度,把你思考得到的关键词(或者怀疑可能出错的地方)当成限定词,你这样再去百度的话,大概率会得到你想要的答案,同时这一思考过程也会大大提升你对知识、工具的理解,锻炼你自己的能力,这点也是极为重要的!

欢迎在评论区留下你的意见和建议,我们可以一起探讨技术,共同进步!

记录点滴,乐于分享,转载请注明出处
愿我们以梦为马,不负人生韶华。
我们追梦在路上!
愿与君共勉!