Mybatis 关联嵌套查询时分页异常的解决思路

问题

当出现嵌套关系,且嵌套关系为 一对多 的时候,分页会出现异常,大致原因就是想分的是 的数据,但是实际上分的是 的数据。

案例 实体

1
2
3
4
5
@lombok.EqualsAndHashCode(callSuper = true)
@lombok.Data
public class UserVo extends User {
private List<Order> orders;
}
1
2
3
4
5
@lombok.Data
public class User {
private Integer userId;
private String userName;
}
1
2
3
4
5
6
@lombok.Data
public class Order {
private Integer orderId;
private Integer userId;
private String orderName;
}

通过 的 select 标签

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
<resultMap id="UserResultMap" type="com.example.demo.pojo.User">
<id column="user_id" jdbcType="INTEGER" property="userId"/>
<result column="user_name" jdbcType="VARCHAR" property="userName"/>
</resultMap>

<resultMap id="OrderResultMap" type="com.example.demo.pojo.Order">
<id column="order_id" jdbcType="INTEGER" property="orderId"/>
<result column="order_name" jdbcType="VARCHAR" property="orderName"/>
</resultMap>

<resultMap id="UserVoResultMap" type="com.example.demo.pojo.vo.UserVo">
<id column="user_id" jdbcType="INTEGER" property="userId"/>
<result column="user_name" jdbcType="VARCHAR" property="userName"/>

<!--
property: 填实体中对应的键
ofType: 返回的类型
select: 对应下面的 select 的 id
column: 传到 select 语句中的参数,{键=值},通过英文逗号分隔可以传多个
-->
<collection property="orders" ofType="com.example.demo.pojo.Order"
select="selectOrder" column="{userId=user_id}"/>
</resultMap>

<!-- 如需分页,在这里增加 -->
<select id="selectVo" resultMap="UserVoResultMap">
select
user_id, user_name
from t_user
</select>

<select id="selectOrder" resultMap="OrderResultMap">
select
order_id, order_name
from t_order where user_id = #{userId}
</select>

缺点:

  • User 查出了多少条记录, 就得查多少次 Order
  • 正常手段没法使用 Order 的查询条件

另一种方式

后面因为产品里一页的记录数正常是 50,就导致效率很低,后面头脑风暴了一下,就多了这种方式。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
<resultMap id="UVoResultMap" type="com.example.demo.pojo.vo.UserVo">
<id column="user_id" jdbcType="INTEGER" property="userId"/>
<result column="user_name" jdbcType="VARCHAR" property="userName"/>

<collection property="orders" ofType="com.example.demo.pojo.Order">
<id column="order_id" jdbcType="INTEGER" property="orderId"/>
<result column="order_name" jdbcType="VARCHAR" property="orderName"/>
</collection>
</resultMap>

<select id="selectPage" parameterType="Object" resultMap="UVoResultMap">
SELECT
v.user_id,
v.user_name,
v.order_id,
v.order_name
FROM
(
SELECT
u.user_id,
u.user_name,
o.order_id,
o.order_name
FROM
t_user u
LEFT JOIN t_order o ON u.user_id = o.user_id
<where ......>
) v
JOIN
(
SELECT
DISTINCT u.user_id
FROM
t_user u
LEFT JOIN t_order o ON u.user_id = o.user_id
<where ......>
LIMIT 0, 50
) d
USING ( user_id )
</select>

缺点就是将语句查多了一次,但总比 50 次好,如果有更优的办法,可以给我留言,或者我自己悟了我再加上。