1. 程式人生 > >mybatis的關聯巢狀查詢--分頁詳解

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