- 场景:
最近做查询酒店订单集合时,需要把酒店订单详情也查出来,酒店订单表 和 酒店订单详情表 是一对多的关系(用订单编号进行关联);最初的做法是 :先去查询酒店订单集合 再循环查询酒店订单详情集合。这么做相当于一次查询要循环执行多次查询,会导致查询效率异常的慢。
所以想找一种方式 一次查询出酒店订单集合并且直接将酒店订单详情集合作为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="com.dhzhly.core.order.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, t.order_amount t_order_amount, t.order_num t_order_num, d.id d_id, d.order_detail_id d_order_detail_id, d.order_num d_order_num, from ( select * from ticket_order where order_num in ( select t1.order_num from ticket_order_detail d1 inner join ticket_order t1 on d1.order_num = t1.order_num <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 d.order_num = t.order_num </select>
-
对于分页数量问题的解决,应该还有其他更优的方案,还望指教。