踩了一个MyBatis的大坑

MySQL left join 看起来变成了inner join?

最近在项目中做了一个上传文件(类云盘)功能。返回文件列表的时候需要left join 用户表,取得上传者的名字。

项目用的是MyBatis,代码写好之后发现,对于每一个上传者,只取到了他上传的最后一个文件,看起来好像是变成了inner join。但是我在MySQL Workbench里面用同样的语句得到的结果是正常的。

一开始我想不通为什么会变成这样,拿inner join去网上查了一下,倒也了解到了MySQL在查询条件为Null-reject的条件下会把outer join 变成inner join。比如官方文档stackoverflow的答案。但是,为什么直接敲SQL是正确的?好像我的问题并不符合上面查到的资料中写的情况。

MyBatis的锅?

既然如此,那锅多半就是MyBatis的了。我先是在mapper的方法那里打了个断点,果然mapper返回的数据就有问题。那么MyBatis执行SQL的结果有没有问题呢?我把日志级别改成了DEBUG,发现SQL返回的结果是没有问题的。果然,是MyBatis哪里出了问题。用不同的关键字去搜索引擎里搜索,发现了这篇博文mybatis 关联查询时,从表只返回第一条记录解决办法 ,对着里面的问题点一条一条地查吧,最后发现,是因为我在resultMap中用到了association,但是没有给这个map指定一个id,也就是这篇博文的第3点。修改之后,问题解决。

比较好的做法是什么?

解决了问题之后,我又重新回去看了一看Mybatis的文档。明确了以下概念:association解决resultMap中has-one的问题,collection解决has-many的问题,这个从标签名字上面就可以看得出来。关于association,文档中有这样一段话:

Very Important: id elements play a very important role in Nested Result mapping. You should always specify one or more properties that can be used to uniquely identify the             results. The truth is that MyBatis will still work if you leave it out, but at a severe performance cost. Choose as few properties as possible that can uniquely identify the result. The primary key is an obvious choice (even if composite).     

强调了指定id的重要性,但并没有说不用id会导致返回结果不正确。尽管如此,经过这次问题,我觉得还是遵守官方文档的推荐做法比较好。

教训总结

  1. 解决问题思路要清晰才能定位准确:既然用SQL都没有问题,那问题多半就在MyBatis,纠结inner join是走偏了;
  2. 调试的时候记得调整日志级别为DEBUG,使用其它语言也是类似的;
  3. 好好读官方文档,文档里推荐的做法也不要不当一回事。
posted @ 2017-09-23 10:48  linden5  阅读(161)  评论(0编辑  收藏  举报