mybatis进阶分页(一对多)

一对多的分页问题
当查询为一对多的时候,进行分页,如果全部查询分页,会以总条数进行分页,而不是以主表条数分页,当分页后,在进行一对多的封装,会导致分页不准

例如: user 表 adress表 一个用户多个收货地址
采用一对多封装
select * from user u left join adress a on a.id = u.adress_id
limit 0,10

当第一个用户有十条地址数据,那么上面的查询0,10,刚好是第一个用户的分页完成,此时再进行一对多封装,将会导致封装之后,仅有一个用户数据,分页不准确

解决办法
1 采用用户主表先查询,然后根据结果,在程序中再次进行查询地址表(不建议)
2 一次性查询,采用一堆多封装(嵌套语句查询)

其实一对多封装有两种,一种是如上的嵌套语句查询,与嵌套结果查询,而如上方式,主表分页则是准确的,第二种嵌套结果查询,主表分页不准确,但是更简洁,更快,我之前的文章有说过嵌套结果查询的例子;

3 采用嵌套结果查询,先不进行分页,根据查询后的结果,进行手动分页(假分页),强制截取结果,其实每次查询的都是全量的,然后截取想要的结果集返回

说明
两种方式都是采用关键字 结果集也都是一对多,不同点在于嵌套语句查询,需要单独执行sql,并指定sql 的入参(关联关键条件)

例子
如下是我自己的一个xml 嵌套语句查询

    <resultMap id="deviceChannelMap" type="com.jovision.vse.console.basic.vo.device.DeviceChannelVo">
        <id column="id" jdbcType="VARCHAR" property="id"/>
        <result column="area_id" jdbcType="VARCHAR" property="areaId"/>
        <result property="realName" column="real_name"/>
        <result property="name" column="name"/>
        <result property="tenantId" column="tenant_id"/>
        <result property="addingMethod" column="adding_method"/>
        <result property="type" column="type"/>
        <result property="areaId" column="area_id"/>
        <result property="sn" column="sn"/>
        <result property="ip" column="ip"/>
        <result property="port" column="port"/>
        <result property="loginName" column="login_name"/>
        <result property="loginPassword" column="login_password"/>
        <result property="remark" column="remark"/>
        <result property="status" column="status"/>
        <result property="extend" column="extend"/>
        <result property="areaName" column="area_name"/>
        <result column="create_user" jdbcType="VARCHAR" property="createUser"/>
        <result column="create_time" jdbcType="TIMESTAMP" property="createTime"/>
        <result column="update_user" jdbcType="VARCHAR" property="updateUser"/>
        <result column="update_time" jdbcType="TIMESTAMP" property="updateTime"/>
        <collection property="channelList"  ofType="com.jovision.vse.console.basic.model.BasicDeviceVideoChannel"
                    select="com.jovision.vse.console.basic.mapper.BasicDeviceMapper.selectChannelList" column="{device_id=id}" />
    </resultMap>


    <select id="selectPage" resultMap="deviceChannelMap">
        SELECT bd.*,ba.name AS area_name
        FROM basic_device bd LEFT JOIN basic_area ba ON ba.id=bd.area_id
        WHERE bd.tenant_id = #{devicePageDto.tenantId}
        <if test="devicePageDto.sn != null and devicePageDto.sn != ''">
            and (bd.sn like concat('%',#{devicePageDto.sn},'%') or bd.name like concat('%',#{devicePageDto.sn},'%'))
        </if>
        <if test="devicePageDto.addingMethod != null and devicePageDto.addingMethod != ''">
            and bd.adding_method = #{devicePageDto.addingMethod}
        </if>
        <if test="devicePageDto.areaIdList != null and devicePageDto.areaIdList.size() != 0">
            and bd.area_id in
            <foreach collection="devicePageDto.areaIdList" item="id" open="(" close=")" separator=",">
                #{id}
            </foreach>
        </if>
        <if test="devicePageDto.status != null and devicePageDto.status != ''">
            and bd.status=#{devicePageDto.status}
        </if>
        ORDER BY bd.update_time DESC
        limit 0,10
    </select>

    <select id="selectChannelList" resultType="com.jovision.vse.console.basic.model.BasicDeviceVideoChannel">
        SELECT
        channel.id ,channel.`channel_enabled`,channel.`channel_status`,channel.`create_time`,
        channel.`create_user`,channel.`update_time`,channel.`update_user`
        ,channel.`device_ability`,channel.`device_id`,channel.`gb_channel_id`,channel.`serial_number`,channel.`name`
        ,channel.`real_name` ,channel.`support_ability`
        FROM  `basic_device_video_channel` channel
        WHERE channel.`device_id` = #{device_id}
    </select>

其中关键点有两个

1.select=“com.jovision.vse.console.basic.mapper.BasicDeviceMapper.selectChannelList”
指定嵌套语句的具体执行语句id
2. column=“{device_id=id}” 指定嵌套语句的关联条件,我将主表的字段id,起了一个别名叫做device_id

这样主表的分页数据就是准确的