1. 什么是延迟加载
延迟加载:就是在需要用到数据时才进行加载,不需要用到数据时就不加载数据,延迟加载也称懒加载。
优点:先从单表查询,需要时再从关联表去关联查询,大大提高数据库性能,因为查询单表要比关联查询多张表速度要快。缺点:因为只有当需要用到数据时,才会进行数据库查询,这样在大批量数据查询时,因为查询工作也要消耗时间,所以可能造成用户等待时间变长,造成用户体验下降。
在上篇博文中,老王已经介绍了MyBatis中一对一(多对一),一对多,多对多关系的配置及实现,可以实现对象的关联查询。以用户和账户一对多的关联关系为例,实际开发过程中很多时候我们并不需要总是在加载用户信息时就一定要加载他的账户信息,此时就是我们所说的延迟加载。我们使用了resultMap来实现一对一(多对一),一对多,多对多关系的操作时,主要是通过association、collection标签来实现,association、collection标签不仅能实现关联关系的映射,还具备延迟加载功能。
2. 一对一(多对一)的延迟加载
编写实体类:
public class User implements Serializable {
private Integer id;
private String username;
private Date birthday;
private String sex;
private String address;
//省略 get和 set方法
}
public class Account implements Serializable {
private Integer id;
private Integer uid;
private Double money
private User user;
//省略 get和 set方法
}
编写持久层接口:
public interface IAccountDao {
List<Account> findAll();
}
public interface IUserDao {
User findById(Integer userId);
}
编写持久层接口的映射文件:
<?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.joker.dao.IAccountDao">
<resultMap id="accountMap" type="com.joker.domain.Account">
<id column="aid" property="id"/>
<result column="uid" property="uid"/>
<result column="money" property="money"/>
<!-- association标签:用于建立一对多中多的一方中的引用实体属性对应关系
* property:指定关联查询的结果集存储在 Account对象的上哪个属性
* javaType:指定关联查询的结果集中的对象类型
* select:指定要调用的 select映射的 id(用户的 dao全限定类名加上方法名称)
* column:指定使用哪个字段的值作为传递给 select映射的参数
-->
<association property="user" javaType="com.joker.domain.User"
select="com.joker.dao.IUserDao.findById" column="uid">
</association>
</resultMap>
<select id="findAll" resultMap="accountMap">
select * from account
</select>
</mapper>
<?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.joker.dao.IUserDao">
<select id="findById" parameterType="int" resultType="com.joker.domain.User">
select * from user where id = #{uid}
</select>
</mapper>
开启MyBatis的延迟加载策略:
我们需要在MyBatis的配置文件SqlMapConfig.xml文件中添加延迟加载的配置:
<!-- 开启延迟加载的支持 -->
<settings>
<setting name="lazyLoadingEnabled" value="true"/>
<setting name="aggressiveLazyLoading" value="false"/>
</settings>
编写测试代码:
@Test
public void testFindAll() {
List<Account> accounts = accountDao.findAll(); //发送一条查询所有账户的 select语句
for(Account au : accounts) {
System.out.println(au);
System.out.println(au.getUser()); //发送一条查询该账户关联的用户的 select语句
}
}
3. 一对多的延迟加载
编写实体类:
public class User implements Serializable {
private Integer id;
private String username;
private Date birthday;
private String sex;
private String address;
private List<Account> accounts;
//省略 get和 set方法
}
public class Account implements Serializable {
private Integer id;
private Integer uid;
private Double money
//省略 get和 set方法
}
编写持久层接口:
public interface IUserDao {
List<User> findAll();
}
public interface IAccountDao {
List<Account> findByUid(Integer uid);
}
编写持久层接口的映射文件:
<?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.joker.dao.IUserDao">
<resultMap id="userMap" type="com.joker.domain.User">
<id column="id" property="id"></id>
<result column="username" property="username"/>
<result column="address" property="address"/>
<result column="sex" property="sex"/>
<result column="birthday" property="birthday"/>
<!-- association标签:用于建立一对多中多的一方中的引用实体属性对应关系
* property:指定关联查询的结果集存储在 Account对象的上哪个属性
* javaType:指定关联查询的结果集中的对象类型
* select:指定要调用的 select映射的 id(账户的 dao全限定类名加上方法名称)
* column:指定使用哪个字段的值作为传递给 select映射的参数
-->
<collection property="accounts" ofType="com.joker.domain.Account"
select="com.joker.dao.IAccountDao.findByUid" column="id">
</collection>
</resultMap>
<select id="findAll" resultMap="userMap">
select * from user
</select>
</mapper>
<?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.joker.dao.IUserDao">
<select id="findByUid" parameterType="int" resultType="com.joker.domain.Account">
select * from account where uid = #{uid}
</select>
</mapper>
编写测试代码:
@Test
public void testFindAll() {
List<User> users = userDao.findAll(); //发送一条查询所有用户的 select语句
for(User user : users) {
System.out.println(user);
System.out.println(user.getAccounts()); //发送一条查询该用户关联的帐户的 select语句
}
}