mybatis一对多映射时始终不能正确映射到实体类,报错:Expected one result (or null) to be returned by selectOne(),but found:

写下这篇博客时真的是痛哭流涕啊,因为有个bug真的让我茶不思,饭不香一整天!那就是

TooManyResultsException: Expected one result (or null) to be returned by selectOne(),but found:13

它的意思就是mybatis期待返回的是一条数据,但实际返回了多条数据。

下面看我的实体类代码,书和章节是一对多关系,所以我在Book里定义了一个BookChapter集合来表示一对多关系,没有错误。
mybatis一对多映射时始终不能正确映射到实体类,报错:Expected one result (or null) to be returned by selectOne(),but found:

然后我的mapper.xml文件是这么映射的:
mybatis一对多映射时始终不能正确映射到实体类,报错:Expected one result (or null) to be returned by selectOne(),but found:
好像。。完全没错啊,到底怎么回事呢?

然后我根据异常各种百度,看了N+1篇博客,都得不到解决。很多博客都是说在mapper.java的接口类中定义的查询方法返回值错了,返回值应该是List集合。
mybatis一对多映射时始终不能正确映射到实体类,报错:Expected one result (or null) to be returned by selectOne(),but found:
可是,我返回的数据确实是只对应一个Book,Book里面对应多个BookChapter啊,返回值是Book没错啊。
mybatis一对多映射时始终不能正确映射到实体类,报错:Expected one result (or null) to be returned by selectOne(),but found:
为什么mybatis不会帮我映射成一个Book实体,而是映射成了多个Book实体,然后报错:Expected one result (or null) to be returned by selectOne(),but found:13

这个bug真的让我找了一天,我反复检查字段名映射是不是出错了,是不是实体类忘了setter方法,但检查了几遍都没发现问题。

然后第二天一觉醒来,灵光一闪。。是不是因为我的sql语句中没有查询主键id(我这里的book_uid不是主键,只是定义成了唯一性,id才是主键),从而导致了mybatis正确映射成一个实体。于是赶紧打开电脑,实验一把发现,还真的是这样。。
mybatis一对多映射时始终不能正确映射到实体类,报错:Expected one result (or null) to be returned by selectOne(),but found:

原来mybatis内部是通过主键id来识别多条数据是否是重复的,如果主键相同,它就会自动帮你过滤掉相同的记录,映射成一个一对多的实体,但如果你没有查询主键,那么mybatis就会视为你的所有数据都是不重复的,因此映射成多个一对多的实体,而你期待的是返回一个实体,自然就会报错TooManyResultsException

所以,有空的话一定要深究一下框架的源码实现,不然找bug都不知道怎么找。。