如何去寻找解决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.csdn.net/qq_46101869/article/details/106910497

案例

好了回归正题,
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FFHKe28f-1592834754218)(media/image44.png)]{width="5.949305555555555in" height="3.3833333333333333in"}

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

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3jIQMgpS-1592834754218)(media/image45.png)]{width="5.761805555555555in" height="3.923611111111111in"}

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

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

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

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xgD3bEPv-1592834754219)(media/image46.png)]{width="5.7652777777777775in" height="2.5256944444444445in"}

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

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lhLJdZAA-1592834754220)(media/image47.png)]{width="7.3493055555555555in" height="4.134722222222222in"}

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

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-935VOvTl-1592834754221)(media/image48.png)]{width="3.7333333333333334in" height="0.2916666666666667in"}

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

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xOySgCVz-1592834754221)(media/image49.png)]{width="5.716666666666667in" height="0.375in"}

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

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

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

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

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

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

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OzSr4kNB-1592834754222)(media/image50.png)]{width="5.759722222222222in" height="3.2402777777777776in"}

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

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

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

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-c5SmxUUw-1592834754223)(media/image51.png)]{width="3.2083333333333335in" height="2.625in"}

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

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Z36E0Xmk-1592834754224)(media/image52.png)]{width="4.45in" height="3.558333333333333in"}

然后呢?

还是找不到…

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

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nPRweG5A-1592834754225)(media/image53.png)]{width="4.216666666666667in" height="4.65in"}

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

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

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

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

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

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-p0USVokk-1592834754227)(media/image54.png)]{width="5.759722222222222in" height="3.2402777777777776in"}

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

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-N0EWl5HT-1592834754228)(media/image55.png)]{width="5.767361111111111in" height="1.9770833333333333in"}

总结

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

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

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

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

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

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

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

猜你喜欢

转载自blog.csdn.net/qq_46101869/article/details/106930544