十二、Mybatis 延迟加载策略
12.1 延迟加载概念
延迟加载:就是在需要用到数据时才进行加载,不需要用到数据时就不加载数据。延迟加载也称懒加载.
好处:先从单表查询,需要时再从关联表去关联查
一对多,多对多:通常情况下我们都是采用延迟加载。
多对一,一对一:通常情况下我们都是采用立即加载。
12.2 实现多对一的延迟加载(association)
需求:查询账户(Account)信息并且关联查询用户(User)信息。如果先查询账户(Account)信息即可满足要求,当我们需要查询用户(User)信息时,再去查询用户信息。
12.2.1 sqlMapConfig.xml 配置文件(*)
如果我们要实现延迟加载,需要在sqlMapConfig.xml文件中添加一个标签 --> <settings>标签
在<settings>中有两个设置名与延迟加载有关,分别是 <lazyLoadingEnabled> 和 <aggressiveLazyLoading>,具体使用可以参考mybatis中的settings设置
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<!--mybatis的核心配置文件-->
<configuration>
<properties resource="jdbc.properties"></properties>
<settings>
<!--延迟加载的全局开关。当开启时,所有关联对象都会延迟加载。 特定关联关系中可通过设置 fetchType 属性来覆盖该项的开关状态。-->
<setting name="lazyLoadingEnabled" value="true"/>
<!--当开启时,任何方法的调用都会加载该对象的所有属性。 否则,每个属性会按需加载-->
<setting name="aggressiveLazyLoading" value="false"/>
</settings>
<typeAliases>
<package name="com.cpz.domain"></package>
</typeAliases>
<environments default="mysql">
<environment id="mysql">
<transactionManager type="JDBC"></transactionManager>
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driver}"></property>
<property name="url" value="${jdbc.url}"></property>
<property name="username" value="${jdbc.username}"></property>
<property name="password" value="${jdbc.password}"></property>
</dataSource>
</environment>
</environments>
<mappers>
<package name="com.cpz.dao"></package>
</mappers>
</configuration>
12.2.2 AccountDao.xml 映像文件的修改
由于我们使用了延迟加载策略,所以在映像文件中要进行相关修改,<resultMap>下的 <association>标签需要与另一个查询语句关联起来。
<?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="com.cpz.dao.AccountDao">
<!--查询账户信息同时查询用户信息。
association:多对一,一对一
property="":属性的名称
javaType="user":对象属性的类型(别名)
column="uid":以查询结果的uid作为查询条件,传递给select指定的查询方法的参数
select="":查询的方法(Dao+方法名称)
fetchType="eager":立即 和延迟检索的局部开关
eager:立即检索
lazy:延迟检索
-->
<resultMap id="accountUserMap" type="account">
<id property="id" column="aid"></id>
<result property="uid" column="uid"></result>
<result property="money" column="money"></result>
<association property="user" javaType="user" column="uid" select="com.cpz.dao.UserDao.findById" fetchType="lazy"></association>
</resultMap>
<select id="findAccountUser" resultMap="accountUserMap">
select * from account
</select>
</mapper>
我们可以看到在 <association> 标签中使用了 select 属性,这里指向的是 UserDao 接口中的 findById() 方法,我们根据查询账户得到的 uid 的值对用户进行查询,查询条件 uid = user.id,这样最后的结果与之前联合语句的结果相同。
结果显示:
这里我们可以看到,在查询的时候只查询了账号的信息,因为本次查询只是将Account对象查询出来放入List集合中,并未涉及User对象的操作,所以没有User对象的查询。
当我们继续执行程序时,发现 用户查询语句被加载,并且账号查询出来的 uid 的值被用作查询的参数传入,进行User对象的查询。
12.3 实现一对多的延迟加载(collection)
需求:查询用户信息同时查询账号信息
12.3.1 sqlMapConfig.xml 文件的修改
这里配置文件的修改和多对一的情况相同,均为开启延迟加载,可以参考前文所述。
12.3.2 UserDao.xml 映像文件的修改
这里只截取了部分重点片段,是在原有代码上进行修改。
<!--collection:一对多,多对多的应用场景,表示集合的映射
property="accounts":表示集合的属性名称
ofType="account":表示集合的类型(别名)
column="id":表示以id的值作为查询条件,传递select指定的方法参数
-->
<resultMap id="userAccountMap" type="user">
<id property="id" column="id"></id>
<result property="username" column="username"></result>
<result property="birthday" column="birthday"></result>
<result property="sex" column="sex"></result>
<result property="address" column="address"></result>
<collection property="accounts" ofType="account" select="com.cpz.dao.AccountDao.findById" column="id" fetchType="lazy"></collection>
</resultMap>
<select id="findUserAccount" resultMap="userAccountMap">
select * from user
</select>
这里的操作和多对一的情况大致相同,一对多使用的是 <collecion> 标签,但其中都使用 select 属性与另一个方法进行关联。
当然我们也需要在 AccountDao 类中创建对应的方法,具体方法可以参考前几篇文章。
结果显示:
由图可以清楚地看出延迟加载的效果,这里不再做说明。