MyBatis | 05.多个collection同时开启延迟加载(使用select属性)时,数据无法正确封装

1.问题描述

在多对多查询的时候

如果一个resultMap中有多个collection同时开启懒加载使用了select属性

那么数据就不会被正确返回

1.1.问题背景:

1) 表中数据如下

image-20210514213246316

2) 班级类:

image-20210514213327509

3) SQL语句和resultMap

image-20210514213120181

其中select对应的SQL语句就是根据stuClassId查询老师和学生,此处省略

1.2.查询结果

我们希望得到的结果是:

返回值是List类型,其中有1个StuClass对象,

3个学生保存在这个对象的studentList属性中

2个老师保存在这个对象的teacherList属性中

但查询出来的结果却是:

返回值是List类型,有6个StuClass对象

每一个StuClass对象都保存了3个学生、2个老师的所有信息

这6个StuClass对象的内容完全一致

image-20210514213725745

2.寻找突破口

2.1.修改其中一个collection

如果其中一个collection使用常规的写法,不写select属性

而另外一个collection保持原样

最终返回的结果就会像期望那样

image-20210514215318723

2.2.修改两个collection

两个collection都不使用select属性,结果自然也是正常返回

此处不多赘述

2.3.注释掉两个collection

查阅资料得知,MyBatis在collection中有select时,执行情况是这样的:

当接收数据的collection有select属性时,

进行主查询时会认为这个resultMap中没有这个collection从而跳过

在主查询执行完毕后,再对主查询的每一个结果执行子查询

换言之:如果主查询返回6个对象,那么就会进行6次子查询

按照上述说法,程序主查询时返回了6个内容一致的对象

为了验证这个结果,直接注释掉两个collection以模拟主查询的结果

返回结果如下

image-20210514220910240

说法得到证实

3.情况分析

有了第三个实验的结果,现在就很明朗了

3.1.注释掉两个collection

在resultMap中没有collection标签时,返回的数据不会去重

查询出几条记录,就会返回几个对象

image-20210514221514460

因此返回了6个一模一样的,只有id和name的StuClass对象

3.2.修改其中一个collection

当collection使用传统的写法,没有用到select属性进行子查询时

MyBatis会自动去重,将数据按照我们的期望去封装

程序的执行步骤如下:

执行主查询时,程序搜索到两个collection:

1) 一个没有select属性的collection(List teacherList)

2) 一个有select属性的collection(List studentList)

此时程序会认为resultMap中只有一个teacherList的collection,另一个collection则会被暂时忽略

得到主查询结果后,teacherList(传统写法)的collection接收数据,将数据去重并重新封装,最终精简成为一个对象,作为主查询的结果

随后执行子查询select,主查询有一个对象,因此执行一次子查询,得到最终想要的结果

3.3.修改两个collection

两个collection都不使用select属性,结果自然也是正常返回

此处不多赘述

4.解决方案

如果两个都必须开启延迟加载,目前来说暂时没有什么好的办法。

可用的解决方案如下:

1) 都不开启延迟加载,不要使用select属性

image-20210514223932745

2) resultMap中只写一个collection,另一个collection的数据在service中进行二次查询,这个可以考虑用一个Util统一实现

部分的核心代码如下,仅供参考:

image-20210514230311814

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值