MyBatis嵌套查詢collection報(bào)錯(cuò):org.apache.ibatis.exceptions.TooManyResultsException
1、目標(biāo)
本文的主要目標(biāo)是研究resultMap的collection更新字段但是resultMap不更新字段報(bào)錯(cuò)的原因和源碼分析
2、resultMap的collection更新字段,resultMap不更新字段會(huì)報(bào)錯(cuò)
<?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字段會(huì)報(bào)錯(cuò)

報(bào)錯(cuò)信息是不能返回多個(gè)記錄,因?yàn)檎{(diào)用了selectOne方法只返回1個(gè)記錄,那為什么會(huì)返回多個(gè)記錄呢,因?yàn)榉庋b成多個(gè)Class班級(jí)對(duì)象了
源碼分析:

查詢數(shù)據(jù)庫(kù)得到多個(gè)記錄后會(huì)調(diào)用handleRowValuesForNestedResultMap方法處理嵌套屬性

會(huì)循環(huán)遍歷查詢數(shù)據(jù)庫(kù)的每個(gè)記錄,并封裝成Class班級(jí)對(duì)象

計(jì)算combinedKey的時(shí)候會(huì)判斷collection的更新字段至少為1并且父節(jié)點(diǎn)resultMap的更新字段至少為1才會(huì)更新combinedKey,否則更新combinedKey是NULL_CACHE_KEY
這里由于resultMap(classMap)的更新字段為0,因此combinedKey是NULL_CACHE_KEY

調(diào)用getRowValue方法查詢數(shù)據(jù)庫(kù)的記錄

會(huì)調(diào)用ObjectFactory對(duì)象的create方法實(shí)例化一個(gè)Class班級(jí)對(duì)象

這里判斷combinedKey等于NULL_CACHE_KEY,因此不會(huì)將這個(gè)Class班級(jí)對(duì)象放到nestedResultObjects這個(gè)map中

while循環(huán)查詢數(shù)據(jù)庫(kù)的第二條記錄的時(shí)候,從nestedResultObjects這個(gè)map中沒(méi)有找到Class班級(jí)對(duì)象就會(huì)創(chuàng)建一個(gè)新的Class班級(jí)對(duì)象,這樣會(huì)返回多個(gè)Class班級(jí)對(duì)象

list集合中添加嵌套王五2Stu對(duì)象的Class班級(jí)對(duì)象,這樣的話會(huì)返回3個(gè)Class班級(jí)對(duì)象

最終查詢數(shù)據(jù)庫(kù)返回3個(gè)Class班級(jí)對(duì)象

調(diào)用selectOne方法查詢數(shù)據(jù)庫(kù)記錄是3個(gè)會(huì)拋出異常:期望1個(gè)返回值結(jié)果返回多個(gè)
3、resultMap的collection和resultMap都更新字段不會(huì)報(bào)錯(cuò)
<?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é)果正確,是一個(gè)Class班級(jí)對(duì)象,同時(shí)封裝了三個(gè)Stu對(duì)象
源碼分析:
public CacheKey clone() throws CloneNotSupportedException {
CacheKey clonedCacheKey = (CacheKey) super.clone();
clonedCacheKey.updateList = new ArrayList<>(updateList);
return clonedCacheKey;
}
執(zhí)行CacheKey的clone方法可以深拷貝CacheKey對(duì)象,這里CacheKey重寫了clone方法,因?yàn)镃acheKey有一個(gè)list集合的屬性u(píng)pdateList,需要手動(dòng)深拷貝復(fù)制list集合屬性

生成combinedKey的時(shí)候會(huì)判斷resultMap的collection的更新字段至少有一個(gè),并且resultMap的更新字段至少有一個(gè),才會(huì)更新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這個(gè)Class班級(jí)對(duì)象

如果combinedKey不為默認(rèn)key即NULL_CACHE_KEY,才會(huì)將查詢數(shù)據(jù)庫(kù)的記錄緩存到nestedResultObjects這個(gè)map中

查詢數(shù)據(jù)庫(kù)的第二條記錄的時(shí)候才會(huì)從nestedResultObjects這個(gè)map中獲取緩存的Class班級(jí)對(duì)象,同時(shí)這個(gè)Class班級(jí)對(duì)象還嵌套了第一條記錄即張三2Stu對(duì)象

查詢的數(shù)據(jù)庫(kù)記錄是一個(gè)記錄,它是Class班級(jí)對(duì)象,它包含了stuList屬性,它是一個(gè)list集合類型,它包括3個(gè)Stu對(duì)象
4、總結(jié)

總結(jié)一句話:resultMap的collection更新字段至少為1個(gè),并且resultMap的更新字段至少為1個(gè),才會(huì)返回一個(gè)嵌套了多個(gè)Stu對(duì)象的Class班級(jí)對(duì)象,否則會(huì)返回多個(gè)Class班級(jí)對(duì)象
到此這篇關(guān)于MyBatis嵌套查詢collection報(bào)錯(cuò):org.apache.ibatis.exceptions.TooManyResultsException的文章就介紹到這了,更多相關(guān)MyBatis嵌套查詢collection報(bào)錯(cuò)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- 解決Mybatis報(bào)錯(cuò):org.apache.ibatis.reflection.ReflectionException: There is no getter for property named問(wèn)題
- 解決mybatis generator MySQL自增ID出現(xiàn)重復(fù)問(wèn)題MySQLIntegrityConstraintViolationException
- 解決springboot3:mybatis-plus依賴錯(cuò)誤:org.springframework.beans.factory.UnsatisfiedDependencyException
- 解決Mybatis出現(xiàn)報(bào)錯(cuò)Error querying database.Cause: java.lang.IndexOutOfBoundsException: Index 9 out of
- 解決mybatis plus報(bào)錯(cuò)com.microsoft.sqlserver.jdbc.SQLServerException:必須執(zhí)行該語(yǔ)句才能獲得結(jié)果
- 關(guān)于MyBatisSystemException異常產(chǎn)生的原因及解決過(guò)程
相關(guān)文章
詳解FutureTask如何實(shí)現(xiàn)最大等待時(shí)間
這篇文章主要為大家詳細(xì)介紹了如何從源碼中了解FutureTask實(shí)現(xiàn)最大等待時(shí)間的方法,文中的示例代碼講解詳細(xì),感興趣的可以了解一下2023-03-03
Java 中的Printstream介紹_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理
PrintStream 是打印輸出流,它繼承于FilterOutputStream。接下來(lái)通過(guò)本文給大家介紹Java 中的Printstream,需要的朋友參考下吧2017-05-05
IDEA版使用Java操作Redis數(shù)據(jù)庫(kù)的方法
這篇文章主要介紹了IDEA版使用Java操作Redis數(shù)據(jù)庫(kù)的方法,首先需要下載jedis.jar包,然后再工程中設(shè)置具體操作步驟跟隨小編一起學(xué)習(xí)下吧2021-08-08
Java如何主動(dòng)從當(dāng)前線程獲取異常信息
這篇文章主要介紹了Java如何主動(dòng)從當(dāng)前線程獲取異常信息,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-10-10
Java Fluent Mybatis實(shí)戰(zhàn)之構(gòu)建項(xiàng)目與代碼生成篇上
Java中常用的ORM框架主要是mybatis, hibernate, JPA等框架。國(guó)內(nèi)又以Mybatis用的多,基于mybatis上的增強(qiáng)框架,又有mybatis plus和TK mybatis等。今天我們介紹一個(gè)新的mybatis增強(qiáng)框架 fluent mybatis2021-10-10

