什么情况下需要延迟加载
在上一讲中有如下JavaBean类
public class Person {
private Integer id;
private String name;
private Integer age;
private IdCard idCard;
private List<BankCard> bankCards;
private List<Role> roles;
//setter getter。。。
}
可以通过如下SQL语句查询出Person的所有信息。
SELECT
person.* ,
id_card.`no` AS id_no,id_card.address,
bank_card.id AS bank_card_id,bank_card.`no` AS bank_card_no,bank_card.amount ,
role.`name` AS role_name,role.duty
FROM person JOIN id_card ON person.id = id_card.person_id
LEFT JOIN bank_card ON person.id = bank_card.fn_person_id
LEFT JOIN person_role ON person.id = person_role.person_id
LEFT JOIN role ON role.id = person_role.role_id
这样做从业务功能的角度是没有问题的。但如果我们只用到Person的姓名和年龄,这时我们仍然要关联查询身份证表、银行卡表、角色表。关联这么多表查询效率就会降低很多,并且查询出来的数据都要在内存里面。如果我们能办到需要什么数据再查什么数据,也就是懒加载,就会大大提高查询效率和节省内存使用。
懒加载的使用
我们可以根据情况对association、collection标签进行懒加载。通常的情况是对列表进行懒加载也就是对应的collection标签。比如上面Person类的银行卡信息、角色信息等。
使用方式
我们对上面的查询进行懒加载处理,比如对身份证信息、银行卡信息、角色信息进行懒加载。
需要在延迟加载的association、collection标签中新增如下3个字段:
- fetchType 有两个取值:(1)lazy : 懒加载 (2)eager :立即加载
- select :当懒加载时,执行的查询的ID(namespace + 语句的ID)。
- column:�执行select语句时传递的参数
MyBatis对应的mapper
<select id="getPersonAllInfoLazy" resultMap="allInfoLazy">
SELECT
person.*
FROM person where id = #{id}
</select>
<resultMap id="allInfoLazy" type="com.lff.beans.Person">
<id property="id" column="id" />
<result property="name" column="name" />
<result property="age" column="age" />
<association property="idCard" javaType="com.lff.beans.IdCard" fetchType="lazy" column="id" select="person.fetchIdCard"/>
<collection property="bankCards" ofType="com.lff.beans.BankCard" fetchType="lazy" column="id" select="person.fetchBankCards" />
<collection property="roles" ofType="com.lff.beans.Role" fetchType="lazy" column="id" select="person.fetchRolesLazy"/>
</resultMap>
<!-- 根据person_id查询身份证-->
<select id="fetchIdCard" parameterType="int" resultType="com.lff.beans.IdCard">
SELECT id_card.* FROM id_card WHERE id_card.person_id = #{id}
</select>
<!-- 根据person_id查询身所有的银行卡-->
<select id="fetchBankCards" parameterType="int" resultMap="bankCardLazyMap">
SELECT bank_card.`no` AS bank_card_no,bank_card.amount amount FROM bank_card WHERE bank_card.fn_person_id = #{id}
</select>
<resultMap id="bankCardLazyMap" type="com.lff.beans.BankCard">
<!-- 这里的属性property都是类BankCard的属性名,column是数据库查询出来的字段-->
<result property="no" column="bank_card_no" />
<result property="amount" column="amount" />
</resultMap>
<!-- 根据person_id查询角色-->
<select id="fetchRolesLazy" resultType="com.lff.beans.Role">
SELECT role.* FROM role JOIN person_role ON role.id = person_role.role_id AND person_role.person_id = #{id}
</select>
可以在MyBatis核心配置文件中设置lazyLoadingEnabled 这样上面的fetchType选项可以省略。
延迟加载的全局开关。当开启时,所有关联对象都会延迟加载。 特定关联关系中可通过设置 fetchType 属性来覆盖该项的开关状态。
<setting name="lazyLoadingEnabled" value="true"/>