今天遇到个需求,是一个一对多的数据,因为数据量过于庞大,导致请求异常缓慢,于是要给这个数据加分业,出现了分页数据条数不正确的问题,先来看看原数据是怎么写的
问题复现
1 2 3 4 5 6 7 8 9
| @Data public class ProjectReceivablesVo implements Serializable { private String projectId; private String customerNo; private String projectNo; ...省略一堆属性... List<DetailedListPurchaseVo> detailedListPurchaseVos; }
|
这是我封装的一个页面的数据,简单来说就是一个项目对应多个清单的一个页面的封装,在不分页的情况下,我们只需要在XML文件里配置好一对多这种映射关系,然后写sql一次性查就好了,像这样
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| <resultMap id="selectprojectReceivablesQuery" type="com.steven.vo.ProjectReceivablesVo"> <id column="project_id" property="projectId"></id> <result column="customer_no" property="customerNo"></result> <result column="project_no" property="projectNo"></result> .....一堆映射..... <collection property="detailedListPurchaseVos" type="com.steven.vo.DetailedListPurchaseVo"> <id column="id" property="id"></id> <result column="did" property="did"></result> <result column="cargo_name" property="cargoName"></result> ....一堆映射..... </collection> </resultMap> <select id="projectReceivablesQuery" resultMap="selectprojectReceivablesQuery"> ....SQL..... </elect>
|
然后Service层直接返回就行
1 2 3 4 5
| @Override public List<ProjectReceivablesVo> projectReceivablesQuery(CargoParam cargoParam) { List<ProjectReceivablesVo> projectReceivablesVo=baseMapper.projectReceivablesQuery(cargoParam); return projectReceivablesVo; }
|
接着,我给查询加了分页,大概是这么个写法
1 2 3 4 5 6
| @Override public IPage<ProjectReceivablesVo> projectReceivablesQuery(CargoParam cargoParam) { Page page=new Page(cargoParam.getCurrent(),cargoParam.getSize()); IPage<ProjectReceivablesVo> iPage=baseMapper.projectReceivablesQuery(page,cargoParam); return iPage; }
|
其中 getCurrent()
是获取前端传过来的起始页,getSize()
是获取前端传过来的每页多少条数据,然后,这是前端传过来的数据:
1 2 3 4
| { "current":1, "size":10 }
|
正常来说,我们应该能得到10条数据

但是,请注意,你能发现,上面的id,有两个一模一样的(图上的10696) 这就导致了一个问题,这里出现的两个其个都是因为父表中id为10696的数据对应着子表的两条数据,所以最终只返回了9条数据给前端(除去那个重复的一个id,只有九条),这很明显分页没正确
解决方法
解决这个的查询方法我理解为将子映射映射到另外的查询上,拆分成两步查询,具体是这样的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| <resultMap id="selectprojectReceivablesQuery" type="com.zncard.management.vo.ProjectReceivablesVo"> <id column="project_id" property="projectId"></id> ****此处省略一堆父映射**** <collection property="detailedListPurchaseVos" column="project_id" select="test" > <id column="id" property="id"></id> ***此处省略一堆子映射*** </collection> </resultMap> <select id="projectReceivablesQuery" resultMap="selectprojectReceivablesQuery"> *****父查询SQL*** </select> <select id="test" resultType="com.zncard.management.vo.DetailedListPurchaseVo"> *****子查询sql*** where project_id=#{project_id} </select>
|
注意,这个 #{project_id}
是父表传过来的父表id,一般设计都是父表id对应好几个子表,以什么对应的就传什么,传入方法请看子映射那里,通过 column="project_id"
传入 映射到了查询名为 test
的查询上我理解为子查询,这样MyBatis-Plus就能正确的处理分页了,或者,直接分成两步查询更直接点(事实上,就应该这样搞),问题解决