大西冰城的博客

MyBatis-Plus如何正置配置一对多关系数据的分页查询

Word count: 924Reading time: 4 min
2021/10/29
loading

今天遇到个需求,是一个一对多的数据,因为数据量过于庞大,导致请求异常缓慢,于是要给这个数据加分业,出现了分页数据条数不正确的问题,先来看看原数据是怎么写的

问题复现

1
2
3
4
5
6
7
8
9
@Data
public class ProjectReceivablesVo implements Serializable {
private String projectId; // 项目id
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就能正确的处理分页了,或者,直接分成两步查询更直接点(事实上,就应该这样搞),问题解决

CATALOG
  1. 1. 问题复现
  2. 2. 解决方法