mybatis<collection>标签使⽤及分页数量问题解决场景:
最近做查询酒店订单集合时,需要把酒店订单详情也查出来,酒店订单表 和 酒店订单详情表 是⼀对多的关系(⽤订单编号进⾏关联);最初的做法是 :先去查询酒店订单集合 再循环查询酒店订单详情集合。这么做相当于⼀次查询要循环执⾏多次查询,会导致查询效率异常的慢。
所以想⼀种⽅式 ⼀次查询出酒店订单集合并且直接将酒店订单详情集合作为list 封装进结果集。于是想到了 <collection>标签。
部分代码及DO类:
订单DO类(其余⽆关字段已省略):
public class TicketOrderAndDetailDO {
分页查询插件private Integer id;
private String orderAmount;//订单⾦额
private String orderNum;
private List<TicketOrderDetailDO> details;//订单详情集合
}
订单详情DO类(其余⽆关字段已省略):
public class TicketOrderDetailDO {
private Integer id;
private String orderDetailId;//订单明细编号
private String orderNum;//订单编号
}
<collection> 有两种使⽤⽅式:
⽅式⼀:
<!-- 这种⽤法依旧相当于循环执⾏sql 效率低下,不使⽤ -->
<resultMap id="RM-TicketOrderAndDetail"type="TicketOrderAndDetailDO">
<result column="t_id"property="id"/>
<result column="order_amount"property="orderAmount"/>
<result column="order_num"property="orderNum"/>
<collection property="details"ofType="TicketOrderDetailDO"column="order_num"javaType="list"
select="rder.persistence.dao.TicketOrderDetailMapper.queryListByOrderNum">
</collection>
</resultMap>
⽅式⼆:
<resultMap id="RM-TicketOrderAndDetail3"type="TicketOrderAndDetailDO">
<result column="t_order_num"property="orderNum"/>
<result column="t_id"property="id"/>
<result column="t_order_amount"property="orderAmount"/>
<collection property="details"ofType="TicketOrderDetailDO"javaType="list">
<result column="d_order_num"property="orderNum"/>
<result column="d_id"property="id"/>
<result column="d_order_detail_id"property="orderDetailId"/>
</collection>
</resultMap>
经过试验发现,⽅式⼀ 虽然和数据库只建⽴了⼀次连接 但是 还是执⾏了查询sql 性能不⾼,所以不使⽤;⽽⽅式⼆ 只执⾏了⼀次sql 效率要搞很多,所以选择⽅式⼆。
<collection>导致的分页数量问题:
使⽤<collection>标签确实实现了⼀对多的⼀次查询,但是遇到⼀个新的问题:分页数量不对。我们项⽬未使⽤分页插件,看⽹友反馈使⽤pagehelper及mybatis plus插件的也遇到了这个问题。
现在就 ⾃⼰⼿写sql 来分析下为什么会出现数量不对以及如何解决:
分页数量为什么不对?
类似下⾯这种常规的分页sql:
select * from table where … limit 0,10
使⽤<collection>封装结果集时,会把内部的数据当成⼀条记录进⾏分页,例如上⾯的例⼦ 有2个订单,每个订单有2个订单详情,本来订单数量应该是2 ,⽽这种情况下 会统计为4。这就导致分页的数量出现问题。
解决⽅法:
使⽤⼦查询:
思路:使⽤⼦查询 查询出符合条件的 外部数据(即酒店订单)对其进⾏分页 ,之后再去关联查询内部数据(即酒店详情订单),这样查询出来的外部数据(即酒店订单)的数量就对了。
<select id="getMerchantHotelOrderList"parameterType="MerchantHotelOrderQuery"resultMap="RM-TicketOrderAndDetail3">
SELECT
t.id t_id,
d.id d_id,
from
(
select * from
ticket_order
where
order_num in
(
select
from
ticket_order_detail d1
inner join
ticket_order t1
on
<where>
<!-- where 条件省略 -->
</where>
) order by id desc
<trim>
<if test="pageSize!=null and pageIndex!=null">
limit #{offset},#{limit}
</if>
</trim>
) t
left join
ticket_order_detail d
on
</select>
对于分页数量问题的解决,应该还有其他更优的⽅案,还望指教。