我们在查询业务数据的时候经常会遇到关联查询的情况,比如查询员工就会关联部门(一对一),查询学生成绩就会关联课程(一对一),查询订单就会关联商品(一对多),等等。
映射结果有两个标签,一个是,一个是。 是select标签的一个属性,适用于返回JDK类型(比如Integer. String等等)和实体类。这种情况下结果集的列和实体类的属性可以直接映射。如果返回的字段无法直接映射,就要用来建立映射关系。 对于关联查询的这种情况,通常不能用来映射。用映射,要么就是修改dto (Data Transfer Object),在里面增加字段,这个会导致增加很多无关的字段。要么就是引用关联的对象,比如Blog里面包含了一个Author对象(多对一),这种情况下就要用到关联查询(association,或者嵌套查询),MyBatis 可以帮我们自动做结果的映射。
association和collection的区别: association是用于一对一和多对一,而collection是用于一对多的关系。 一对一的关联查询有两种配置方式:
嵌套结果
代码语言:javascript复制 <!-- 根据文章查询作者,一对一查询的结果,嵌套查询 -->
<resultMap id="BlogWithAuthorResultMap" type="com.gupaoedu.domain.associate.BlogAndAuthor">
<id column="bid" property="bid" jdbcType="INTEGER"/>
<result column="name" property="name" jdbcType="VARCHAR"/>
<!-- 联合查询,将author的属性映射到ResultMap -->
<association property="author" javaType="com.gupaoedu.domain.Author">
<id column="author_id" property="authorId"/>
<result column="author_name" property="authorName"/>
</association>
</resultMap>
嵌套查询
代码语言:javascript复制 <!-- 另一种联合查询(一对一)的实现,但是这种方式有“N 1”的问题 -->
<resultMap id="BlogWithAuthorQueryMap" type="com.gupaoedu.domain.associate.BlogAndAuthor">
<id column="bid" property="bid" jdbcType="INTEGER"/>
<result column="name" property="name" jdbcType="VARCHAR"/>
<association property="author" javaType="com.gupaoedu.domain.Author"
column="author_id" select="selectAuthor"/> <!-- selectAuthor 定义在下面-->
</resultMap>
<!-- 嵌套查询 -->
<select id="selectAuthor" parameterType="int" resultType="com.gupaoedu.domain.Author">
select author_id authorId, author_name authorName
from author where author_id = #{authorId}
</select>
其中第二种方式:嵌套查询,由于是分两次查询,当我们查询了Blog 信息之后,会再发送一条SQL到数据库查询部门信息。
我们只执行了一次查询Blog信息的SQL(所谓的1),如果返回了N条记录(比如10条Blog),因为一个Blog就有至少一个Author,就会再发送N条到数据库查询Author信息(所谓的N),这个就是我们所说的N 1的问题。这样会白白地浪费我们的应用和数据库的性能。 如果我们用了嵌套查询的方式,怎么解决这个问题?能不能等到使用Author 信息的时候再去查询?这个就是我们所说的延迟加载,或者叫懒加载。 在MyBatis里面可以通过开启延迟加载的开关来解决这个问题。
延迟加载
在settings标签里面可以配置:
代码语言:javascript复制 <!-- 延迟加载的全局开关。当开启时,所有关联对象都会延迟加载。默认 false -->
<setting name="lazyLoadingEnabled" value="true"/>
<!-- 当开启时,任何方法的调用都会加载该对象的所有属性。默认 false,可通过select标签的 fetchType来覆盖-->
<setting name="aggressiveLazyLoading" value="true"/>
<!-- Mybatis 创建具有延迟加载能力的对象所用到的代理工具,默认JAVASSIST -->
<setting name="proxyFactory" value="CGLIB" />
lazyLoadingEnabled决定了是否延迟加载(默认false)。 aggressiveLazyLoading决定了是不是对象的所有方法都会触发查询。