一、问题现象
在mybatis的resultMap标签中使用collection或者assocation做嵌套结果映射,再配合PageHalper实现分页效果的时候,会出现两个问题:
-
实际查出来的数据,会部分丢失,比如传的页面大小是10条,那么有可能会返回小于10条记录。 -
分页对象的total总数与实际返回的数量不一致。
二、问题原因
在定位问题前,我们先了解下PageHalper的工作原理,PageHapler主要是通过拦截器实现的,在执行sql前会根据页码和页数在sql的后面加上关键字,比如limit,rownum等。
在PageHapler拦截SQL添加分页关键字成功后,由于嵌套结果集的方式会导致结果集被折叠,因此分页查询后的结果在折叠后总数会减少,所以无法保证分页结果数量正确。
在PageHapler官网的常见问题列表中也有对此问题的说明:
为什么不支持一对一和一对多结果映射的分页查询?
在一对一和一对多时,根据分页条件查询出 100 条数据时,由于一对一和一对多会去重,经过嵌套处理后数据量会减少,因此分页想要获得 100 条数据无法实现。想要支持这种情况可以使用嵌套查询。嵌套查询是要额外执行SQL,主SQL可以得到正确的结果数量,因此可以正常分页。
三、解决方法
-
使用mybatis的嵌套查询,在resultMap的collection标签中使用select属性额外执行SQL,如果数据量比较大的时候,可能对性能影响严重。
<resultMap id="list" type="com.xxx.xxx.entity.xxxxxxx">
<id column="id_" property="id"/>
<result column="name_" property="name"/>
<collection property="users"
javaType="java.util.ArrayList"
ofType="com.xxx.xxx.xxx.xxx"
select="com.xxx.xxx.xxx.xxx.xxxx"
column="{id=id_}"/>
</resultMap> -
在业务层service中,拿到主SQL的结果集,再传入条件去执行额外SQL获取结果集。