mybatis的關聯巢狀查詢--分頁詳解
問題描述
1. mybatis巢狀查詢後,分頁混亂:mybatis通過查詢結果之後摺疊結果集把資料放在了集合裡,這就導致總條數的混亂.而第一種的方式是分兩次查詢,分頁只針對第一次查詢,就不會有分頁的問題,所以解決方案就是把你的collection寫成第一種的方式
2. 摺疊結果集對映不上資料
1. 資料庫
-- 區域表: CREATE TABLE `area` ( `id` bigint(11) NOT NULL AUTO_INCREMENT, `parent_id` bigint(11), `area_name` varchar(100), `area_code` varchar(32), PRIMARY KEY (`id`) USING BTREE ) ; -- 裝置表 CREATE TABLE `device` ( `id` bigint(11) NOT NULL AUTO_INCREMENT, `area_id` bigint(11), `device_name` varchar(64), `device_code` varchar(36), `device_type` varchar(36), PRIMARY KEY (`id`) USING BTREE );
關聯說明:區域表和裝置表是一對多的關係
2. 實體類
// 區域類的DTO package com.device.dto; import lombok.Data; import java.util.List; @Data // 此註解提供了實體類get和set方法 public class AreaOutpDTO { private Long id; private Long parentId; private String areaName; private String areaCode; private List<DeviceTypeNumDTO> devices; // 裝置數量DTO集合 } // 裝置數量的DTO,注意這裡不是直接的裝置類,而是對裝置型別和數量的一個統計,若是裝置類的話,則也沒有那麼複雜了 package com.device.dto; import lombok.Data; @Data public class DeviceTypeNumDTO { private String deviceType; // 裝置型別 private Long deviceNum; // 裝置數量 }
3. Mapper 檔案的編寫
<resultMap id="AreaOutpDTOMap" type="com.device.dto.AreaOutpDTO"> <id column="id" jdbcType="BIGINT" property="id" /> <result column="parent_id" jdbcType="VARCHAR" property="parentId" /> <result column="area_name" jdbcType="VARCHAR" property="areaName" /> <result column="area_code" jdbcType="VARCHAR" property="areaCode" /> <!-- 裝置 型別數量集合 --> <collection property="devices" ofType="com.device.dto.DeviceTypeNumDTO" select="selectDeviceTypeNumDTO" column="id"> <!-- 下面這兩行可以不用寫,但寫了也不會通過它對映,只能通過下面的DeviceTypeNumDTOMap進行對映 --> <!-- <result column="device_type" jdbcType="VARCHAR" property="deviceType" /> <result column="device_num" jdbcType="BIGINT" property="deviceNum" />--> </collection> </resultMap> <!-- 此Map必須寫,否則資料無法對映到devices中 --> <resultMap id="DeviceTypeNumDTOMap" type="com.device.dto.DeviceTypeNumDTO"> <result column="device_type" jdbcType="VARCHAR" property="deviceType" /> <result column="device_num" jdbcType="BIGINT" property="deviceNum" /> </resultMap> <select id="listSubArea" resultMap="AreaOutpDTOMap"> select a.id, a.parent_id, a.area_name, a.area_code, from area a where a.parent_id = #{areaId} </select> <select id="selectDeviceTypeNumDTO" resultMap="DeviceTypeNumDTOMap"> select d.device_type, count(*) device_num from device d group by d.device_type, d.area_id having d.area_id = #{id} </select>
注意事項:(大坑) 開始沒有寫DeviceTypeNumDTOMap,而是將對映的欄位寫在collection中,發現無論如何都不能在摺疊結果集中取到資料,而SQL卻又是被呼叫了的。
上述Mapper的處理過程:
在呼叫mapper介面中的listArea
方法,首先呼叫SQLselect a.id,a.parent_id, a.area_name,a.area_code,from area a where a.parent_id = #{areaId}
,從資料庫中拿到返回資料之後,開始做返回值對映,此時的返回值對映物件是一個resultMap
(id:AreaOutpDTOMap),該resultMap實際上是一個AreaOutpDTO
的例項,因此在開始做對映的時候,id和 parent_id,area_name,area_code,因為屬性名和資料庫返回值一致完成對映,但是到了devices
屬性的時候,發現他是一個collection
集合物件,裡面存放的是DeviceTypeNumDTO例項,那怎麼獲取裡面的資料?看collection標籤的屬性,他需要關聯一個查詢操作select="selectDeviceTypeNumDTO"
獲取其資料,即通過select d.device_type, count(*) device_num from device d group by d.device_type, d.area_id having d.area_id = #{id}
獲取collection中的資料,select="selectPer"
操作需要傳入資料,傳入的資料column="id"
即是第一次查詢中返回的id
,最後一步,就是將第二次查詢出來的資料對映到collection中,切記一定要寫一個ResultMap
來接受,不能直接在collection中新增欄位來對映。
4. 分頁的處理
經過上面的Mapper對映後,呼叫PageHelper外掛已經是對摺疊後的結果集進行分頁了,成功解決分頁總數混亂的問題
@Override
public List<AreaOutpDTO> listSubArea(Integer page, Integer size, String orderBy, Long areaId) {
PageHelper.startPage(page, size, orderBy);
return areaMapper.listSubArea(areaId, categoryId);
}
5. 如果不分頁,則採用mybatis的第二種分頁方式
僅改動Mapper檔案,其餘相同
<resultMap id="AreaOutpDTOMap" type="com.device.dto.AreaOutpDTO">
<id column="id" jdbcType="BIGINT" property="id" />
<result column="parent_id" jdbcType="BIGINT" property="parentId" />
<result column="area_name" jdbcType="VARCHAR" property="areaName" />
<result column="area_code" jdbcType="VARCHAR" property="areaCode" />
<collection property="devices" ofType="com.device.dto.DeviceTypeNumDTO">
<result column="device_type" jdbcType="VARCHAR" property="deviceType" />
<result column="device_num" jdbcType="BIGINT" property="deviceNum" />
</collection>
</resultMap>
<select id="listArea" resultMap="AreaOutpDTOMap">
select
a.id,
a.parent_id,
a.area_name,
a.area_code,
c.device_type,
c.device_num
from area a
left join (
select
d.area_id, d.device_type, count(*) device_num
from device d
group by d.device_type, d.area_id) c
on a.id = c.area_id
where a.parent_id = #{areaId}
</select>
轉載請註明出處:https://blog.csdn.net/qq_34997906/article/details/84498115