• Mybatis plus 一对多关联查询分页不准确的问题


    场景说明

    比如有个服务器管理页面。要显示服务器信息,并且包含其拥有的账号信息。展示示例如下:
    在这里插入图片描述
    表结构信息如下:

    t_server

    在这里插入图片描述

    t_server_user

    在这里插入图片描述

    查询sql

    select
    	ts.id,
    	ts.host,
    	tsu.id as user_id,
    	tsu.user_name ,
    	tsu.server_id ,
    	tsu.port
    from
    	t_server ts
    left join t_server_user tsu on
    	ts.id = tsu.server_id
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    查询结果

    在这里插入图片描述

    问题点

    我们在代码中定义的ResultMap

    <resultMap id="QueryServerResultMap" type="com.yyoo.deployer.beans.ServerBean" extends="com.yyoo.deployer.mapper.ServerMapper.BaseResultMap">
            <collection property="userList"  ofType="com.yyoo.deployer.entity.ServerUserBean">
                <id column="user_id" property="id"/>
                <result column="user_name" property="userName" />
                <result column="pass" property="pass" />
                <result column="port" property="port" />
                <result column="server_id" property="serverId"/>
            collection>
        resultMap>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    此处我们使用了collection标签。Mybatis会自动把上面的查询结果进行归类,形成一个server对象对应多个serverUser对象的形式。
    这样做,不分页的时候是没有问题的。关键是分页的时候。

    Mybatis在分页的时候生成的sql如下(下面均为查询第一页每页10条数据)

    select
    	ts.id,
    	ts.host,
    	tsu.id as user_id,
    	tsu.user_name ,
    	tsu.server_id ,
    	tsu.port
    from
    	t_server ts
    left join t_server_user tsu on
    	ts.id = tsu.server_id
    	limit 10 offset 0
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    此语句的查询结果为:(为了方便区分,结果为红框部分)
    在这里插入图片描述

    按照我们的规则,最终形成的ServerBean其实只有6条。

    解决办法

    1. 在 collection 标签上使用子查询

    该办法会有n+1查询的问题,此处我们就不做详细讲解了。

    2. 重新计算分页的limit参数

    该办法计算起来有点难度,我们也不做讲解

    3. 自定义分页查询sql

    其实造成这个问题的关键在于,sql查询返回的条数,和Mybatis最终组装后的结果bean的条数不一致。要一致的关键在于,我们的查询主体是Server,我们将sql改造为如下方式

    select
    	ts.id,
    	ts.host,
    	tsu.id as user_id,
    	tsu.user_name ,
    	tsu.server_id ,
    	tsu.port
    from
    	(select * from t_server limit 10 offset 0 ) ts
    left join t_server_user tsu on
    	ts.id = tsu.server_id
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    直接将分页参数编写好,查询第一页的10条server信息。

    注:采用此方式,我们就不能使用Mybatis的分页机制了,参数不能使用Mybatis-plus的Page对象,需要自定义分页信息,采用list返回,而且还得自定义 count 的查询语句。配套的 count查询语句如下

    select count(id)
            from t_server ts
    
    • 1
    • 2

    我们的分页和前端显示都是针对server,所以此处的count查询也只针对server。

  • 相关阅读:
    (附源码)ssm汽车租赁——持续输出BU 毕业设计 271621
    xilinx FPGA ROM IP核的使用(VHDL&ISE)
    Android ADB 常用命令及详解
    JavaFX入门和网格布局面板的使用,Dao层交互,舞台与场景切换以及其他控件的使用
    【JavaWeb从入门到实战】MySQL筑基&初探SQL
    PendingIntent
    不同类型的软件企业该如何有效的管理好你的软件测试团队?
    Objective-C编写程序
    达人评测 i7 12800hx和i9 12900h选哪个好
    设计有效的异常测试用例:关注这些方向,保障软件稳定性
  • 原文地址:https://blog.csdn.net/forlinkext/article/details/127803724