解决MyBatis一对多分页查询不匹配条数的问题

本文介绍了一对多关系下MyBatis后台分页的优化方法,通过调整SQL语句解决分页时显示记录数不准确的问题。适用于需要展示主表及从表信息的场景。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在开发过程中,写mybatis后台分页时(不会后台分页的可以参考我的这篇博客https://blog.youkuaiyun.com/geng2568/article/details/88042834,),要求展示主表信息加从表信息实现分页,并且主表和从表的关系是一对多,这样在写后台分页过程中,每页显示的信息总会少于要求显示的信息,这是因为在一对多左关联查询时,从表中有多少个和主表对应的数据,查询结果中就有几条主表信息和从表对应。总之:

 原先的sql是:

<select id="getServerInfoPage" resultMap="BaseResultMap" parameterType="java.util.Map" >
    SELECT
    sm.*,vm.id vmid,vm.v_user_name vusername,vm.password vmpassword,vm.v_big_internet,
    vm.big_mask_code,vm.big_gateway,vm.small_mask_code,
    vm.small_internet,vm.use_person, vm.operate_system,
    vm.application vmapplication,vm.remark vmremark
    FROM server_manager sm
    LEFT JOIN
    virtual_machine_info vm
    ON
    sm.id = vm.server_id
    <where>
      <if test="serverBrand != null and serverBrand != ''" >
        and sm.server_brand like concat('%',#{serverBrand,jdbcType=VARCHAR},'%')
      </if>
      <if test="serverType != null and serverType != ''" >
        and sm.server_type like concat('%',#{serverType,jdbcType=VARCHAR},'%')
      </if>
      <if test="serverPosition != null and serverPosition != ''" >
        and sm.server_position like concat('%',#{serverPosition,jdbcType=VARCHAR},'%')
      </if>
      <if test="userName != null and userName != ''" >
        and sm.user_name = #{userName,jdbcType=VARCHAR}
      </if>
      <if test="password != null and password != ''" >
        and sm.password = #{password,jdbcType=VARCHAR}
      </if>
    </where>
        ORDER BY id asc
        LIMIT #{pageStart},#{pageSize}
    </select>

改正之后的sql: 

<select id="getServerInfoPage" resultMap="BaseResultMap" parameterType="java.util.Map" >
    SELECT
    sm.*,vm.id vmid,vm.v_user_name vusername,vm.password vmpassword,vm.v_big_internet,
    vm.big_mask_code,vm.big_gateway,vm.small_mask_code,
    vm.small_internet,vm.use_person, vm.operate_system,
    vm.application vmapplication,vm.remark vmremark
    FROM server_manager sm
    LEFT JOIN
    virtual_machine_info vm
    ON
    sm.id = vm.server_id
    <where>
      sm.id IN (SELECT test.id from (SELECT id FROM server_manager  LIMIT #{pageStart},#{pageSize}) AS test)
      <if test="serverBrand != null and serverBrand != ''" >
        and sm.server_brand like concat('%',#{serverBrand,jdbcType=VARCHAR},'%')
      </if>
      <if test="serverType != null and serverType != ''" >
        and sm.server_type like concat('%',#{serverType,jdbcType=VARCHAR},'%')
      </if>
      <if test="serverPosition != null and serverPosition != ''" >
        and sm.server_position like concat('%',#{serverPosition,jdbcType=VARCHAR},'%')
      </if>
      <if test="userName != null and userName != ''" >
        and sm.user_name = #{userName,jdbcType=VARCHAR}
      </if>
      <if test="password != null and password != ''" >
        and sm.password = #{password,jdbcType=VARCHAR}
      </if>
      <if test="hardpan != null and hardpan !=''" >
        and sm.hardpan = #{hardpan,jdbcType=VARCHAR}
      </if>
      <if test="memory != null and memory != ''" >
        and sm.memory = #{memory,jdbcType=VARCHAR}
      </if>
      <if test="cpu != null and cpu!=''" >
        and sm.cpu = #{cpu,jdbcType=VARCHAR}
      </if>
      <if test="bigInternet != null and bigInternet !=''" >
        and sm.big_internet like concat('%',#{bigInternet,jdbcType=VARCHAR},'%')
      </if>
      <if test="maskCode != null and maskCode !=''" >
        and sm.mask_code like concat('%',#{maskCode,jdbcType=VARCHAR},'%')
      </if>
     </where>
        ORDER BY id asc
     </select>

总之:基本sql需要加强锻炼,以后再遇到这种情况就能够得心应手了,希望可以帮助遇到类似错误的小伙伴,加油!!!! 

 

 

### MyBatis 中实现左连接一对多分查询 在处理数据库查询,特别是在涉及复杂关系的数据表之间执行操作MyBatis 提供了强大的功能来简化开发人员的工作。对于左连接(`LEFT JOIN`)的一对多分查询场景,可以采用如下方式: #### SQL 查询语句设计 为了有效地获取父实体及其关联子实体列表并应用分逻辑,在构建 `SELECT` 语句需注意几点事项: - 使用外键约束定义两个表之间的联系; - 利用聚合函数如 `GROUP_CONCAT()` 或者窗口函数根据具体需求收集相关记录; - 应用合适的索引来优化性能。 针对一对多的关系模型,假设存在两张表分别为订单(`orders`)和订单项(`order_items`),其中每条订单可能对应多个订单项,则可以通过下面的方式编写SQL: ```sql SELECT o.*, GROUP_CONCAT(oi.item_id) AS item_ids FROM orders o LEFT JOIN order_items oi ON o.order_id = oi.order_id WHERE o.status = 'active' AND (o.customer_name LIKE '%${searchText}%' OR EXISTS ( SELECT 1 FROM order_items WHERE order_id=o.order_id AND product_name LIKE '%${searchText}%' )) ORDER BY o.create_time DESC LIMIT #{start},#{size} ``` 此段代码实现了基于关键词模糊匹配的条件过滤以及按创建间降序排列的结果集截取[^1]。 #### Mapper XML 文件配置 接着是在Mapper文件里声明相应的接口方法签名,并映射上述自定义SQL到Java对象上。这里展示了一个简单的例子用于说明如何设置resultMap属性从而完成复杂的嵌套结构转换工作: ```xml <resultMap id="OrderWithItemsResult" type="com.example.Order"> <id property="orderId" column="order_id"/> <!-- other columns mapping --> <collection property="items" ofType="com.example.Item"> <id property="itemId" column="item_id"/> <!-- other Item properties mappings --> </collection> </resultMap> <select id="findOrdersByPage" resultMap="OrderWithItemsResult" parameterType="map"> ${selectSqlString} </select> ``` 此处利用了 `<collection>` 标签指定集合类型的成员变量名及元素类别;而 `${}` 表达式的运用允许动态拼接部分SQL片段以适应同上下文环境下的调用需求[^2]。 #### Java Service 层封装 最后一步就是在服务层内组装好必要的参数并通过调用DAO层暴露出来的API达成最终目的——即返回带有分信息的对象实例给控制器层面做进一步渲染呈现: ```java public Page<Order> findOrderByPage(String searchText, int page, int size){ Map<String,Object> params=new HashMap<>(); String selectSql= "SELECT o.*, GROUP_CONCAT(DISTINCT oi.item_id SEPARATOR ',') as items"; params.put("selectSql",selectSql); params.put("searchText",searchText); params.put("start",(page-1)*size); params.put("size",size); List<Order> list=mapper.findOrdersByPage(params); long total=mapper.countTotalRecords(searchText); // 另一个单独的count查询 return new Page<>(list,total,page,size); } ``` 以上便是有关于MyBatis框架下实施带有限制条件的左联结一对多模式并且支持分特性的整体解决方案概述[^3]。
评论 13
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值