MyBatis嵌套查詢collection報錯:org.apache.ibatis.exceptions.TooManyResultsException
1、目標(biāo)
本文的主要目標(biāo)是研究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字段會報錯
報錯信息是不能返回多個記錄,因為調(diào)用了selectOne方法只返回1個記錄,那為什么會返回多個記錄呢,因為封裝成多個Class班級對象了
源碼分析:
查詢數(shù)據(jù)庫得到多個記錄后會調(diào)用handleRowValuesForNestedResultMap方法處理嵌套屬性
會循環(huán)遍歷查詢數(shù)據(jù)庫的每個記錄,并封裝成Class班級對象
計算combinedKey的時候會判斷collection的更新字段至少為1并且父節(jié)點(diǎn)resultMap的更新字段至少為1才會更新combinedKey,否則更新combinedKey是NULL_CACHE_KEY
這里由于resultMap(classMap)的更新字段為0,因此combinedKey是NULL_CACHE_KEY
調(diào)用getRowValue方法查詢數(shù)據(jù)庫的記錄
會調(diào)用ObjectFactory對象的create方法實例化一個Class班級對象
這里判斷combinedKey等于NULL_CACHE_KEY,因此不會將這個Class班級對象放到nestedResultObjects這個map中
while循環(huán)查詢數(shù)據(jù)庫的第二條記錄的時候,從nestedResultObjects這個map中沒有找到Class班級對象就會創(chuàng)建一個新的Class班級對象,這樣會返回多個Class班級對象
list集合中添加嵌套王五2Stu對象的Class班級對象,這樣的話會返回3個Class班級對象
最終查詢數(shù)據(jù)庫返回3個Class班級對象
調(diào)用selectOne方法查詢數(shù)據(jù)庫記錄是3個會拋出異常:期望1個返回值結(jié)果返回多個
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
最后輸出結(jié)果正確,是一個Class班級對象,同時封裝了三個Stu對象
源碼分析:
public CacheKey clone() throws CloneNotSupportedException { CacheKey clonedCacheKey = (CacheKey) super.clone(); clonedCacheKey.updateList = new ArrayList<>(updateList); return clonedCacheKey; }
執(zhí)行CacheKey的clone方法可以深拷貝CacheKey對象,這里CacheKey重寫了clone方法,因為CacheKey有一個list集合的屬性updateList,需要手動深拷貝復(fù)制list集合屬性
生成combinedKey的時候會判斷resultMap的collection的更新字段至少有一個,并且resultMap的更新字段至少有一個,才會更新combinedKey,否則combinedKey設(shè)置成默認(rèn)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不為默認(rèn)key即NULL_CACHE_KEY,才會將查詢數(shù)據(jù)庫的記錄緩存到nestedResultObjects這個map中
查詢數(shù)據(jù)庫的第二條記錄的時候才會從nestedResultObjects這個map中獲取緩存的Class班級對象,同時這個Class班級對象還嵌套了第一條記錄即張三2Stu對象
查詢的數(shù)據(jù)庫記錄是一個記錄,它是Class班級對象,它包含了stuList屬性,它是一個list集合類型,它包括3個Stu對象
4、總結(jié)
總結(jié)一句話:resultMap的collection更新字段至少為1個,并且resultMap的更新字段至少為1個,才會返回一個嵌套了多個Stu對象的Class班級對象,否則會返回多個Class班級對象
到此這篇關(guān)于MyBatis嵌套查詢collection報錯:org.apache.ibatis.exceptions.TooManyResultsException的文章就介紹到這了,更多相關(guān)MyBatis嵌套查詢collection報錯內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- 解決Mybatis報錯:org.apache.ibatis.reflection.ReflectionException: There is no getter for property named問題
- 解決mybatis generator MySQL自增ID出現(xiàn)重復(fù)問題MySQLIntegrityConstraintViolationException
- 解決springboot3:mybatis-plus依賴錯誤:org.springframework.beans.factory.UnsatisfiedDependencyException
- 解決Mybatis出現(xiàn)報錯Error querying database.Cause: java.lang.IndexOutOfBoundsException: Index 9 out of
- 解決mybatis plus報錯com.microsoft.sqlserver.jdbc.SQLServerException:必須執(zhí)行該語句才能獲得結(jié)果
- 關(guān)于MyBatisSystemException異常產(chǎn)生的原因及解決過程
相關(guān)文章
Java 中的Printstream介紹_動力節(jié)點(diǎn)Java學(xué)院整理
PrintStream 是打印輸出流,它繼承于FilterOutputStream。接下來通過本文給大家介紹Java 中的Printstream,需要的朋友參考下吧2017-05-05IDEA版使用Java操作Redis數(shù)據(jù)庫的方法
這篇文章主要介紹了IDEA版使用Java操作Redis數(shù)據(jù)庫的方法,首先需要下載jedis.jar包,然后再工程中設(shè)置具體操作步驟跟隨小編一起學(xué)習(xí)下吧2021-08-08Java Fluent Mybatis實戰(zhàn)之構(gòu)建項目與代碼生成篇上
Java中常用的ORM框架主要是mybatis, hibernate, JPA等框架。國內(nèi)又以Mybatis用的多,基于mybatis上的增強(qiáng)框架,又有mybatis plus和TK mybatis等。今天我們介紹一個新的mybatis增強(qiáng)框架 fluent mybatis2021-10-10