MyBatis多表联查返回List仅一条数据?主键冲突BUG排查与解决方案

 更新时间:2026年04月09日 16:54:45   作者:Tech_Jia_Hui  
在项目开发中,通过MyBatis实现“管理员-角色-权限”多表关联查询时,遇到SQL执行返回多条结果但MyBatis映射后List集合只显示一条数据的BUG,最终定位到是主键字段命名冲突导致,通过为SQL中同名字段起别名并修正ResultMap配置,成功修复了BUG

一、问题背景

在项目开发中,多表联查是高频需求。近期在基于MyBatis实现"管理员-角色-权限"多表关联查询时,遇到了一个诡异的BUG:数据库执行SQL能返回多条正确结果,但项目中通过MyBatis映射后,List集合始终只显示一条数据。

经过反复排查,最终定位到是主键字段命名冲突导致MyBatis数据映射异常,现将完整排查过程与解决方案分享如下。

二、问题复现

2.1 业务场景

需通过管理员ID查询该管理员的基本信息、关联的角色列表,以及每个角色对应的权限列表,涉及admin(管理员表)、role(角色表)、permission(权限表)三张核心表,通过中间表admin_rolerole_permission实现关联。

2.2 核心代码实现

1. Mapper.xml查询SQL

SELECT
    a.id,
    a.username,
    r.id,
    r.role_name,
    r.role_desc,
    p.id,
    p.permission_name,
    p.url
FROM
    `admin` a
    LEFT JOIN admin_role ON a.id = admin_role.aid
    LEFT JOIN `role` r ON admin_role.rid = r.id
    LEFT JOIN role_permission ON r.id = role_permission.rid
    LEFT JOIN permission p ON role_permission.pid = p.id
WHERE
    a.id = #{aid}

直接在数据库执行该SQL,返回2条结果(对应2个权限),数据正常。

2. ResultMap配置

<resultMap id="adminMapper" type="com.lion.online.pojo.Admin">
    <id property="id" column="id"></id>
    <result property="username" column="username"></result>
    <!-- 角色列表关联 -->
    <collection property="roles" column="id" ofType="com.lion.online.pojo.Role">
        <id property="id" column="id"></id>
        <result property="roleName" column="role_name"></result>
        <result property="roleDesc" column="role_desc"></result>
        <!-- 权限列表关联 -->
        <collection property="permissions" column="id" ofType="com.lion.online.pojo.Permission">
            <id property="id" column="id"/>
            <result property="permissionName" column="permission_name"></result>
            <result property="url" column="url"></result>
        </collection>
    </collection>
</resultMap>

3. 异常结果

项目运行后,控制台打印SQL执行结果为2条,但页面仅显示1条权限数据,List集合长度异常为1。

三、BUG根源分析

3.1 核心问题:字段名冲突

MyBatis的ResultMap中,id标签用于标识实体类的主键字段,其column属性对应查询结果集中的列名(而非数据库表字段名)。本案例中:

  • 管理员表、角色表、权限表的主键均命名为id
  • 查询SQL未对多表中的id字段起别名,导致结果集中出现多个同名id
  • MyBatis在映射数据时,无法区分主表(admin)、关联表(role、permission)的id字段,误将所有id列值当作主表主键处理,最终只保留了一条去重后的数据

3.2 关键原理

ResultMapid标签具有"数据唯一标识"的作用,MyBatis会根据id字段的值判断是否为同一实体。

当多表id字段同名且未区分时,MyBatis会认为所有关联数据属于同一个实体,从而覆盖重复数据,导致最终返回结果条数少于实际查询结果。

四、解决方案

核心思路:通过SQL别名区分多表中的同名id字段,在ResultMap中明确映射对应关系。

4.1 优化查询SQL(添加字段别名)

对角色表id起别名rid,权限表id起别名pid,避免列名冲突:

SELECT
    a.id,
    a.username,
    r.id AS rid,  -- 角色ID别名
    r.role_name,
    r.role_desc,
    p.id AS pid,  -- 权限ID别名
    p.permission_name,
    p.url
FROM
    `admin` a
    LEFT JOIN admin_role ON a.id = admin_role.aid
    LEFT JOIN `role` r ON admin_role.rid = r.id
    LEFT JOIN role_permission ON r.id = role_permission.rid
    LEFT JOIN permission p ON role_permission.pid = p.id
WHERE
    a.id = #{aid}

4.2 修正ResultMap配置(映射别名列)

更新ResultMapcollection标签的column属性,指向SQL中定义的别名:

<resultMap id="adminMapper" type="com.lion.online.pojo.Admin">
    <!-- 管理员主表映射 -->
    <id property="id" column="id"></id>
    <result property="username" column="username"></result>
    <!-- 角色列表关联:column指向角色ID别名rid -->
    <collection property="roles" column="rid" ofType="com.lion.online.pojo.Role">
        <id property="id" column="rid"></id>  <!-- 角色主键映射别名列 -->
        <result property="roleName" column="role_name"></result>
        <result property="roleDesc" column="role_desc"></result>
        <!-- 权限列表关联:column指向权限ID别名pid -->
        <collection property="permissions" column="pid" ofType="com.lion.online.pojo.Permission">
            <id property="id" column="pid"/>  <!-- 权限主键映射别名列 -->
            <result property="permissionName" column="permission_name"></result>
            <result property="url" column="url"></result>
        </collection>
    </collection>
</resultMap>

4.3 优化说明

  1. SQL别名命名规范:建议采用"表名首字母+id"的格式(如rid=role_id、pid=permission_id),提高可读性
  2. collection标签的column属性:需与SQL别名完全一致,确保MyBatis能正确匹配关联数据
  3. 主键映射优先级:id标签的映射优先级高于result标签,必须优先确保主键字段映射正确

五、验证结果

优化后重新运行项目,页面成功展示所有关联数据:

List集合长度与数据库查询结果一致,BUG修复完成。

六、避坑总结

  1. 多表联查必注意:只要涉及多张表,必须对同名字段起别名,尤其是主键id
  2. ResultMap映射原则:column属性对应"查询结果集的列名",而非数据库表字段名,别名变更需同步更新

七、总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • Spring框架的JdbcTemplate使用

    Spring框架的JdbcTemplate使用

    它是 Spring 框架中提供的一个对象,是对原始 Jdbc API 对象的简单封装。本文就来介绍一下Spring框架的JdbcTemplate使用,感兴趣的可以了解一下
    2021-09-09
  • SpringMVC工作原理实例详解

    SpringMVC工作原理实例详解

    这篇文章主要介绍了SpringMVC工作原理实例详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-03-03
  • Java Synchronized锁的使用详解

    Java Synchronized锁的使用详解

    在多线程并发问题中,常用Synchronized锁解决问题。本篇文章主要介绍了并发编程中Synchronized锁的用法知识记录,感兴趣的小伙伴可以了解一下
    2022-10-10
  • Spring的BeanUtils.copyProperties属性复制避坑指南

    Spring的BeanUtils.copyProperties属性复制避坑指南

    这篇文章主要介绍了Spring的BeanUtils.copyProperties属性复制避坑指南,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-08-08
  • java 算法之归并排序详解及实现代码

    java 算法之归并排序详解及实现代码

    这篇文章主要介绍了java 算法之归并排序详解及实现代码的相关资料,需要的朋友可以参考下
    2017-03-03
  • java能写爬虫程序吗

    java能写爬虫程序吗

    在本篇文章里小编给大家整理的是一篇关于java是否能写爬虫程序的一篇文章,对此有兴趣的朋友们可以学习下。
    2021-01-01
  • 获取JsonObject某一未知key的值操作

    获取JsonObject某一未知key的值操作

    这篇文章主要介绍了获取JsonObject某一未知key的值操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2021-01-01
  • 统一建模语言_动力节点Java学院整理

    统一建模语言_动力节点Java学院整理

    这篇文章主要介绍了统一建模语言的相关知识,非常不错,具有参考借鉴价值,需要的的朋友参考下吧
    2017-06-06
  • Java中Collection与Collections的区别详解

    Java中Collection与Collections的区别详解

    这篇文章主要为大家详细介绍了Java中Collection与Collections的区别,文中有详细的代码示例,具有一定的参考价值,感兴趣的同学可以参考一下
    2023-06-06
  • 升级springboot3.x踩坑记录

    升级springboot3.x踩坑记录

    本文主要介绍了升级springboot3.x踩坑记录,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2024-05-05

最新评论