MyBatis嵌套查询collection报错:org.apache.ibatis.exceptions.TooManyResultsException

 更新时间:2024年09月27日 11:07:05   作者:永不服输的coder  
本文主要介绍了MyBatis嵌套查询collection报错:org.apache.ibatis.exceptions.TooManyResultsException,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

1、目标

本文的主要目标是研究resultMap的collection更新字段但是resultMap不更新字段报错的原因和源码分析

2、resultMap的collection更新字段,resultMap不更新字段会报错

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.apache.mybatisDemo.ClassMapper">
    <resultMap id="classMap" type="org.apache.mybatisDemo.Class">
        <!--<id property="id" column="classId"/>-->
        <!--<result property="name" column="className"/>-->
        <!--<result property="createTime" column="create_time"/>-->
        <collection property="stuList" javaType="java.util.List" ofType="org.apache.mybatisDemo.Stu">
            <result property="id" column="stuId"/>
            <result property="name" column="stuName"/>
            <result property="age" column="age"/>
        </collection>
    </resultMap>

    <select id="getClass" resultMap="classMap">
        select c.id classId, c.name className, c.create_time, s.id stuId, s.name stuName, s.age
        from `class` c inner join `stu` s on c.id = s.class_id
        where c.`name` = #{className}
    </select>
</mapper>

如果不更新resultMap是classMap的字段只更新resultMap的collection字段会报错

在这里插入图片描述

报错信息是不能返回多个记录,因为调用了selectOne方法只返回1个记录,那为什么会返回多个记录呢,因为封装成多个Class班级对象了

源码分析:

在这里插入图片描述

查询数据库得到多个记录后会调用handleRowValuesForNestedResultMap方法处理嵌套属性

在这里插入图片描述

会循环遍历查询数据库的每个记录,并封装成Class班级对象

在这里插入图片描述

计算combinedKey的时候会判断collection的更新字段至少为1并且父节点resultMap的更新字段至少为1才会更新combinedKey,否则更新combinedKey是NULL_CACHE_KEY

这里由于resultMap(classMap)的更新字段为0,因此combinedKey是NULL_CACHE_KEY

在这里插入图片描述

调用getRowValue方法查询数据库的记录

在这里插入图片描述

会调用ObjectFactory对象的create方法实例化一个Class班级对象

在这里插入图片描述

这里判断combinedKey等于NULL_CACHE_KEY,因此不会将这个Class班级对象放到nestedResultObjects这个map中

在这里插入图片描述

while循环查询数据库的第二条记录的时候,从nestedResultObjects这个map中没有找到Class班级对象就会创建一个新的Class班级对象,这样会返回多个Class班级对象

在这里插入图片描述

list集合中添加嵌套王五2Stu对象的Class班级对象,这样的话会返回3个Class班级对象

在这里插入图片描述

最终查询数据库返回3个Class班级对象

在这里插入图片描述

调用selectOne方法查询数据库记录是3个会抛出异常:期望1个返回值结果返回多个

3、resultMap的collection和resultMap都更新字段不会报错

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.apache.mybatisDemo.ClassMapper">
    <resultMap id="classMap" type="org.apache.mybatisDemo.Class">
        <id property="id" column="classId"/>
        <result property="name" column="className"/>
        <result property="createTime" column="create_time"/>
        <collection property="stuList" javaType="java.util.List" ofType="org.apache.mybatisDemo.Stu">
            <result property="id" column="stuId"/>
            <result property="name" column="stuName"/>
            <result property="age" column="age"/>
        </collection>
    </resultMap>

    <select id="getClass" resultMap="classMap">
        select c.id classId, c.name className, c.create_time, s.id stuId, s.name stuName, s.age
        from `class` c inner join `stu` s on c.id = s.class_id
        where c.`name` = #{className}
    </select>
</mapper>

resultMap更新字段大于1,并且resultMap的collection的更新字段也大于1

在这里插入图片描述

最后输出结果正确,是一个Class班级对象,同时封装了三个Stu对象

源码分析:

public CacheKey clone() throws CloneNotSupportedException {
    CacheKey clonedCacheKey = (CacheKey) super.clone();
    clonedCacheKey.updateList = new ArrayList<>(updateList);
    return clonedCacheKey;
  }

执行CacheKey的clone方法可以深拷贝CacheKey对象,这里CacheKey重写了clone方法,因为CacheKey有一个list集合的属性updateList,需要手动深拷贝复制list集合属性

在这里插入图片描述

生成combinedKey的时候会判断resultMap的collection的更新字段至少有一个,并且resultMap的更新字段至少有一个,才会更新combinedKey,否则combinedKey设置成默认key即NULL_CACHE_KEY

这里combinedKey=-1902729450:-2918070140:org.apache.mybatisDemo.ClassMapper.mapper_resultMap[classMap]_collection[stuList]:stuId:4:stuName:张三2:age:15:680594160:-729303444:org.apache.mybatisDemo.ClassMapper.classMap:classId:2

它由两部分组成,第一部分是collection的key和value,第二部分是classMap这个Class班级对象

在这里插入图片描述

如果combinedKey不为默认key即NULL_CACHE_KEY,才会将查询数据库的记录缓存到nestedResultObjects这个map中

在这里插入图片描述

查询数据库的第二条记录的时候才会从nestedResultObjects这个map中获取缓存的Class班级对象,同时这个Class班级对象还嵌套了第一条记录即张三2Stu对象

在这里插入图片描述

查询的数据库记录是一个记录,它是Class班级对象,它包含了stuList属性,它是一个list集合类型,它包括3个Stu对象

4、总结

在这里插入图片描述

总结一句话:resultMap的collection更新字段至少为1个,并且resultMap的更新字段至少为1个,才会返回一个嵌套了多个Stu对象的Class班级对象,否则会返回多个Class班级对象

到此这篇关于MyBatis嵌套查询collection报错:org.apache.ibatis.exceptions.TooManyResultsException的文章就介绍到这了,更多相关MyBatis嵌套查询collection报错内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • SpringBoot3使用Jasypt实现配置文件信息加密的方法

    SpringBoot3使用Jasypt实现配置文件信息加密的方法

    对于一些单体项目而言,在没有使用SpringCloud的情况下,配置文件中包含着大量的敏感信息,如果这些信息泄露出去将会对企业的资产产生重大威胁,因此,对配置文件中的敏感信息加密是一件极其必要的事,所以本文介绍了SpringBoot3使用Jasypt实现配置文件信息加密的方法
    2024-07-07
  • SpringSecurity授权实现基本思路

    SpringSecurity授权实现基本思路

    本文介绍了SpringSecurity中使用FilterSecurityInterceptor进行权限校验的基本方法,通过SecurityContextHolder获取Authentication中的权限信息,感兴趣的朋友跟随小编一起看看吧
    2024-10-10
  • java 获取数据库连接的实现代码

    java 获取数据库连接的实现代码

    本篇文章是对在java中获取数据库连接的实现代码进行了详细的分析介绍,需要的朋友参考下
    2013-05-05
  • Spring中使用copyProperties方法进行对象之间的属性赋值详解

    Spring中使用copyProperties方法进行对象之间的属性赋值详解

    这篇文章主要介绍了Spring中使用copyProperties方法进行对象之间的属性赋值详解,使用org.springframework.beans.BeanUtils.copyProperties方法进行对象之间属性的赋值,避免通过get、set方法一个一个属性的赋值,需要的朋友可以参考下
    2023-12-12
  • java并发学习之Executor源码解析

    java并发学习之Executor源码解析

    这篇文章主要为大家介绍了java并发学习之Executor源码示例解析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-07-07
  • SpringBoot+log4j2.xml使用application.yml属性值问题

    SpringBoot+log4j2.xml使用application.yml属性值问题

    这篇文章主要介绍了SpringBoot+log4j2.xml使用application.yml属性值问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2023-12-12
  • Spring切面优先级与基于xml的AOP实现方法详解

    Spring切面优先级与基于xml的AOP实现方法详解

    这篇文章主要介绍了Spring切面的优先级与基于xml的AOP的详细步骤,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-11-11
  • JAVA字符串占位符使用方法实例

    JAVA字符串占位符使用方法实例

    今天同事又问起类似符串占位符使用的功能,所以下面这篇文章主要给大家介绍了关于JAVA字符串占位符使用的相关资料,文中通过实例代码介绍的非常详细,需要的朋友可以参考下
    2022-11-11
  • SpringBoot详细介绍SPI机制示例

    SpringBoot详细介绍SPI机制示例

    这篇文章主要介绍了深入解析Spring Boot的SPI机制详情,SPI是JDK内置的一种服务提供发现机制,可以用来启用框架扩展和替换组件,主要用于框架中开发,更多相关介绍,感兴趣的小伙伴可以参考一下下面文章内容
    2022-08-08
  • Java超详细讲解多态的调用

    Java超详细讲解多态的调用

    多态就是指程序中定义的引用变量所指向的具体类型和通过该引用变量发出的方法调用在编程时并不确定,而是在程序运行期间才确定,即一个引用变量到底会指向哪个类的实例对象,该引用变量发出的方法调用到底是哪个类中实现的方法,必须在由程序运行期间才能决定
    2022-05-05

最新评论