Mybatis 的嵌套查询与嵌套结果的区别

什么是嵌套查询和嵌套结果

嵌套查询 是指通过执行另外一条 SQL 映射语句来返回预期的复杂类型;

嵌套结果 是使用嵌套结果映射来处理重复的联合结果的子集。

开发人员可以使用上述任意一种方式实现对关联关系的加载。

区别

嵌套查询 嵌套结果
嵌套查询是在查询 SQL 后再进行一个(子)查询 嵌套结果是一个多表查询的 SQL 语句
会执行多条 SQL 语句 只有一条复杂的 SQL 语句(多表连接)
SQL语句编写较为简单 SQL语句编写较为复杂

以下给出简单代码比较二则区别:

	<!-- 嵌套查询:通过执行另外一条SQL映射语句来返回预期的特殊类型 -->
	<resultMap id="BaseResultMap" type="com.eucheng.eusys.eusyspersonnel.domain.Depts">
        <id column="id" jdbcType="INTEGER" property="id"/>
        <result column="name" jdbcType="VARCHAR" property="name"/>
        <result column="parent_id" jdbcType="INTEGER" property="parentId"/>
        <result column="level" jdbcType="VARCHAR" property="level"/>
        <result column="remark" jdbcType="VARCHAR" property="remark"/>
    </resultMap>
    <resultMap id="DeptsWithChildren" extends="BaseResultMap" type="com.eucheng.eusys.eusyspersonnel.domain.Depts">
        <collection property="childrens" ofType="com.eucheng.eusys.eusyspersonnel.domain.Depts"
                    select="getAllDepartmentsByParentId" column="id"/>
    </resultMap>
	<select id="getAllDepartmentsByParentId" parameterType="java.lang.Integer" resultMap="DeptsWithChildren">
        select
        id, `name`, parent_id, `level`, remark
        from dept
        where parent_id = #{parent_id,jdbcType=INTEGER}
    </select>
	
	<!-- 嵌套结果:使用嵌套结果映射来处理重复的联合结果的子集 -->
	<select id="findPersonById2" parameterType="Integer" 
	                                   resultMap="IdCardWithPersonResult2">
	    SELECT p.*,idcard.code
	    from tb_person p,tb_idcard idcard
	    where p.card_id=idcard.id 
	    and p.id= #{id}
	</select>
	<resultMap type="Person" id="IdCardWithPersonResult2">
	    <id property="id" column="id" />
	    <result property="name" column="name" />
	    <result property="age" column="age" />
	    <result property="sex" column="sex" />
	    <association property="card" javaType="IdCard">
	        <id property="id" column="card_id" />
	        <result property="code" column="code" />
	    </association>
	</resultMap>

嵌套查询的执行过程是:

 ==>  Preparing: select id, `name`, parent_id, `level`, remark from dept where parent_id = ?
 ==> Parameters: -1(Integer)
 ====>  Preparing: select id, `name`, parent_id, `level`, remark from dept where parent_id = ?
 ====> Parameters: 0(Integer)
 ======>  Preparing: select id, `name`, parent_id, `level`, remark from dept where parent_id = ?
 ======> Parameters: 1(Integer)
 ========>  Preparing: select id, `name`, parent_id, `level`, remark from dept where parent_id = ?
 ========> Parameters: 2(Integer)
 <========      Total: 0
 ========>  Preparing: select id, `name`, parent_id, `level`, remark from dept where parent_id = ?
 ========> Parameters: 3(Integer)
 <========      Total: 0
 <======      Total: 2
 ======>  Preparing: select id, `name`, parent_id, `level`, remark from dept where parent_id = ?
 ======> Parameters: 4(Integer)
 ========>  Preparing: select id, `name`, parent_id, `level`, remark from dept where parent_id = ?
 ========> Parameters: 5(Integer)
 <========      Total: 0
 ========>  Preparing: select id, `name`, parent_id, `level`, remark from dept where parent_id = ?
 ========> Parameters: 6(Integer)
 <========      Total: 0
 <======      Total: 2
 .....以下差不多相同就不截取了

嵌套结果的执行过程是:

嘿嘿没有不想写,就是只有一个 SQL 语句,多表联查的那种。看参考1人家截图去。

嵌套查询的弊端

嵌套查询的N+1问题:

尽管嵌套查询大量的简化了存在关联关系的查询,但它的弊端也比较明显:即所谓的N+1问题。关联的嵌套查询显示得到一个结果集,然后根据这个结果集的每一条记录进行关联查询。
现在假设嵌套查询就一个(即resultMap 内部就一个association标签),现查询的结果集返回条数为N,那么关联查询语句将会被执行N次,加上自身返回结果集查询1次,共需要访问数据库N+1次。如果N比较大的话,这样的数据库访问消耗是非常大的!所以使用这种嵌套语句查询的使用者一定要考虑慎重考虑,确保N值不会很大。
嵌套语句的查询会导致数据库访问次数不定,进而有可能影响到性能。

摘自:mybatis的嵌套查询与嵌套结果查询的不同

总结

所以多表查询还是用嵌套结果,而嵌套查询应该用在单表,阶级。比如上面的部门结构,因为不确定部门的子部门有多少层,所以没有办法使用嵌套结果查询。

参考

探索嵌套查询和嵌套结果这对孪生子的秘密!!!

mybatis的嵌套查询与嵌套结果查询的不同

mybatis 中文文档 --- XML 映射器

posted @ 2021-04-13 17:32  东郊  阅读(9174)  评论(0编辑  收藏  举报