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值不会很大。
嵌套语句的查询会导致数据库访问次数不定,进而有可能影响到性能。
总结
所以多表查询还是用嵌套结果,而嵌套查询应该用在单表,阶级。比如上面的部门结构,因为不确定部门的子部门有多少层,所以没有办法使用嵌套结果查询。