1、嵌套结果:
(mybatis-standalone - MyBatisTest - testSelectBlogWithAuthorResult ())
<!-- 根据文章查询作者,一对一查询的结果,嵌套查询-->
<resultMap id="BlogWithAuthorResultMap"
type="com.leon.domain.associate.BlogAndAuthor">
<id column="bid" property="bid" jdbcType="INTEGER"/>
<result column="name" property="name" jdbcType="VARCHAR"/>
<!-- 联合查询,将author 的属性映射到ResultMap -->
<association property="author" javaType="com.leon.domain.Author">
<id column="author_id" property="authorId"/>
<result column="author_name" property="authorName"/>
</association>
</resultMap>
2、嵌套查询:
(mybatis-standalone - MyBatisTest - testSelectBlogWithAuthorQuery ())
<!-- 另一种联合查询(一对一)的实现,但是这种方式有“N+1”的问题-->
<resultMap id="BlogWithAuthorQueryMap" type="com.leon.domain.associate.BlogAndAuthor">
<id column="bid" property="bid" jdbcType="INTEGER"/>
<result column="name" property="name" jdbcType="VARCHAR"/>
<association property="author" javaType="com.leon.domain.Author"
column="author_id" select="selectAuthor"/> <!-- selectAuthor 定义在下面-->
</resultMap>
<!-- 嵌套查询-->
<select id="selectAuthor" parameterType="int" resultType="com.leon.domain.Author">
select author_id authorId, author_name authorName
from author where author_id = #{authorId}
</select>
其中第二种方式:嵌套查询,由于是分两次查询,当我们查询了员工信息之后,会再发送一条SQL 到数据库查询部门信息。
我们只执行了一次查询员工信息的SQL(所谓的1),如果返回了N 条记录,就会再发送N 条到数据库查询部门信息(所谓的N),这个就是我们所说的N+1 的问题。这样会白白地浪费我们的应用和数据库的性能。
如果我们用了嵌套查询的方式,怎么解决这个问题?能不能等到使用部门信息的时候再去查询?这个就是我们所说的延迟加载,或者叫懒加载。
在MyBatis 里面可以通过开启延迟加载的开关来解决这个问题。
在settings 标签里面可以配置:
<!--延迟加载的全局开关。当开启时,所有关联对象都会延迟加载。默认false -->
<setting name="lazyLoadingEnabled" value="true"/>
<!--当开启时,任何方法的调用都会加载该对象的所有属性。默认false,可通过select 标签的
fetchType 来覆盖-->
<setting name="aggressiveLazyLoading" value="false"/>
<!-- Mybatis 创建具有延迟加载能力的对象所用到的代理工具,默认JAVASSIST -->
<setting name="proxyFactory" value="CGLIB" />
lazyLoadingEnabled 决定了是否延迟加载。
aggressiveLazyLoading 决定了是不是对象的所有方法都会触发查询。
先来测试一下(也可以改成查询列表):
1、没有开启延迟加载的开关,会连续发送两次查询;
2 、开启了延迟加载的开关, 调用blog.getAuthor() 以及默认的(equals,clone,hashCode,toString)时才会发起第二次查询,其他方法并不会触发查询,比如blog.getName();
3、如果开启了aggressiveLazyLoading=true,其他方法也会触发查询,比如blog.getName()。
问题:为什么可以做到延迟加载?blog.getAuthor(),只是一个获取属性的方法,里面并没有连接数据库的代码,为什么会触发对数据库的查询呢?
我怀疑:blog 根本不是Blog 对象,而是被人动过了手脚!
把这个对象打印出来看看:
System.out.println(blog.getClass());
果然不对:
class com.leon.domain.associate.BlogAndAuthor_$$_jvst70_0
这个类的名字后面有jvst,是JAVASSIST 的缩写。原来到这里带延迟加载功能的对象blog 已经变成了一个代理对象,那到底什么时候变成代理对象的?我们后面在看源码的时候再去分析,这个也先留一个作业给大家。