Mybatis的延迟加载
一、什么是延迟加载
延迟加载: 就是在需要用到数据时才进行加载,不需要用到数据时就不加载数据。延迟加载也称懒加载.好处: 先从单表查询,需要时再从关联表去关联查询,大大提高数据库性能,因为查询单表要比关联查询多张表速度要快。坏处: 因为只有当需要用到数据时,才会进行数据库查询,这样在大批量数据查询时,因为查询工作也要消耗时间,所以可能造成用户等待时间变长,造成用户体验下降。
二、实现需求
需求: 查询账户(Account)信息并且关联查询用户(User)信息。如果先查询账户(Account)信息即可满足要求,当我们需要查询用户(User)信息时再查询用户(User)信息。把对用户(User)信息的按需去查询就是延迟加载。 association、collection 具备延迟加载功能。
三、使用association实现延迟加载
需求:
查询账户信息同时查询用户信息。
3.1 账户的持久层dao接口
package com.llb.dao;import com.llb.domain.Account;import java.util.List;/** * Ceate By llb on 2019/8/7
*/publicinterface AccountMapper {
/** * 查询账户所对应的的用户
*/ List findAccountAndUser();
}
3.2 账户的持久层映射文件
<?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.llb.dao.AccountMapper">
<!--定义封装account和user的resultMap-->
<resultMap id="accountMap" type="com.llb.domain.Account">
<id property="id" column="id"></id>
<result property="uid" column="uid"></result>
<result property="money" column="money"></result>
<!--一对一的关系映射 JavaType:对应的是哪个类 select 指定的内容:查询用户的唯一标识 -->
<association property="user" column="uid" javaType="com.llb.domain.User" select="com.llb.dao.UserMapper.findById" ></association> </resultMap>
<select id="findAccountAndUser" resultMap="accountMap"> select * from account </select>
</mapper>
3.3 用户的持久层接口
package com.llb.dao;import com.llb.domain.User;import java.util.List;/** * 用户的持久层接口
* Ceate By llb on 2019/8/5
*/publicinterface UserMapper {
/** * 根据id查询所有用户
* @return*/ User findById(Integer id);
/** * 查询出所有用户,包含账户信息
* @return*/ List findAccountAndUser();
}
3.4 用户的持久层映射文件
<?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.llb.dao.UserMapper">
<!--配置 查询结果的列名和实体类的属性名的对应关系-->
<resultMap id="userMap" type="com.llb.domain.User">
<id property="id" column="id"></id>
<result property="username" column="username"></result>
<result property="address" column="address"></result>
<result property="sex" column="sex"></result>
<result property="birthday" column="birthday"></result>
<!--配置user对象中accounts集合的映射 ofType:表示集合的类型-->
<collection property="accounts" ofType="com.llb.domain.Account">
<id property="id" column="aid"></id>
<result property="uid" column="uid"></result>
<result property="money" column="money"></result>
</collection>
</resultMap> <!--查询出用户所对应的账户-->
<select id="findAccountAndUser" resultMap="userMap"> select * from user left outer join account on user.id = account.uid </select> <!--根据id查询用户--> <select id="findById" resultType="user" parameterType="int"> select * from user where id = #{id} </select></mapper>
3.5 开启mybatis的延迟加载策略
进入 Mybaits 的官方文档,找到 settings 的说明信息:
我们需要在 Mybatis 的配置文件 SqlMapConfig.xml 文件中添加延迟加载的配置。
<!--配置参数,延迟加载-->
<settings>
<!--开启mybatis支持延迟加载-->
<setting name="lazyLoadingEnabled" value="true"/>
<!--不配置也可以:默认为false;允许触发方法进行延迟加载,否则立即加载-->
<setting name="aggressiveLazyLoading" value="false"></setting>
</settings>
3.6 编写测试只查账户信息不查用户信息
*/publicclass AccountTest {
InputStream in =null;
AccountMapper mapper =null;
SqlSession sqlSession =null;
/** * 在测试方法执行前执行
* @throws IOException
*/ @Before
publicvoidinit()throws IOException {
//1.读取配置文件,生成字节流in = Resources.getResourceAsStream("SqlMapConfig.xml");
//2.获取sqlSessionFactory对象SqlSessionFactory factory =new SqlSessionFactoryBuilder().build(in);
//3.获取sqlSession对象sqlSession = factory.openSession();
//4.获取dao的代理对象mapper = sqlSession.getMapper(AccountMapper.class);
}
/** * 测试方法执行后执行
* @throws IOException
*/ @After
publicvoiddestory()throws IOException {
sqlSession.commit();
//6.释放资源 sqlSession.close();
in.close();
}
/** * 查询出账户所对应的user
*/ @Test
publicvoid testFindAccountAndUser(){
List accountUser = mapper.findAccountAndUser();// for (Account account: accountUser) {// System.out.println(account);// } }
}
3.7 测试结果
当不进行配置时,立即加载,查询account所对应的user,一起将user查询出来:
配置后,对account进行查询放入到list集合中,并没有涉及到user对象,所以就没有发出 SQL 语句查询账户所关联的 User 对象的查询。:
四、使用collection实现缓存策略
同样我们也可以在一对多关系配置的<collection>结点中配置延迟加载策略。
<collection>结点中也有 select 属性,column 属性。
需求:
完成加载用户对象时,查询该用户所拥有的账户信息。
4.1 在User实体类中加入List<Account>属性
package com.llb.domain;import java.io.Serializable;
import java.util.Date;import java.util.List;/** * Ceate By llb on 2019/8/5
*/publicclassUserimplements Serializable{
private Integer id;
private String username;
private String address;
private String sex;
private Date birthday;
//一对多关系。一的方包含多的一方所有对象privateList accounts;
@Override
public String toString() {
return"User{" + "id=" + id + ", username='" + username + '\'' + ", address='" + address + '\'' + ", sex='" + sex + '\'' + ", birthday=" + birthday + ", accounts=" + accounts + '}';
}
publicList getAccounts() {
return accounts;
}
publicvoidsetAccounts(List accounts) {
this.accounts = accounts;
}
public Integer getId() {
return id;
}
publicvoid setId(Integer id) {
this.id = id;
}
public String getUsername() {
return username;
}
publicvoid setUsername(String username) {
this.username = username;
}
public String getAddress() {
return address;
}
publicvoid setAddress(String address) {
this.address = address;
}
public String getSex() {
return sex;
}
publicvoid setSex(String sex) {
this.sex = sex;
}
public Date getBirthday() {
return birthday;
}
publicvoid setBirthday(Date birthday) {
this.birthday = birthday;
}
}
4.2 编写用户接口和配置文件
UserMapper.class:
package com.llb.dao;import com.llb.domain.User;import java.util.List;/** * 用户的持久层接口
* Ceate By llb on 2019/8/5
*/publicinterface UserMapper {
/** * 根据id查询所有用户
* @return*/ User findById(Integer id);
/** * 查询出所有用户,包含账户信息
* @return*/ List findAccountAndUser();
}
UserMapper.xml:
<?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.llb.dao.UserMapper">
<!--配置 查询结果的列名和实体类的属性名的对应关系-->
<resultMap id="userMap" type="com.llb.domain.User">
<id property="id" column="id"></id>
<result property="username" column="username">
</result> <result property="address" column="address">
</result> <result property="sex" column="sex">
</result> <result property="birthday" column="birthday">
</result>
<!--配置user对象中accounts集合的映射 ofType:表示集合的类型-->
<collection property="accounts" ofType="com.llb.domain.Account" select="com.llb.dao.AccountMapper.findAccountById" column="id"> </collection>
</resultMap> <!--查询出用户所对应的账户-->
<select id="findAccountAndUser" resultMap="userMap">
select * from user
</select>
<!--根据id查询用户-->
<select id="findById" resultType="user" parameterType="int">
select * from user where id = #{id}
</select>
</mapper>
4.3 使用测试方法进行测试
publicclass UserTest {
InputStream in =null;
UserMapper mapper =null;
SqlSession sqlSession =null;
/** * 在测试方法执行前执行
* @throws IOException
*/ @Before
publicvoidinit()throws IOException {
//1.读取配置文件,生成字节流in = Resources.getResourceAsStream("SqlMapConfig.xml");
//2.获取sqlSessionFactory对象SqlSessionFactory factory =new SqlSessionFactoryBuilder().build(in);
//3.获取sqlSession对象sqlSession = factory.openSession();
//4.获取dao的代理对象mapper = sqlSession.getMapper(UserMapper.class);
}
/** * 测试方法执行后执行
* @throws IOException
*/ @After
publicvoiddestory()throws IOException {
sqlSession.commit();
//6.释放资源 sqlSession.close();
in.close();
}
/** * 查询出所有用户所对应的账户
*/ @Test
publicvoid findUserAndAccount(){
List users = mapper.findAccountAndUser();
}
}
测试结果:
我们没有使用Accout,也只对User进行了查询。
Mybatis缓存
源码:https://github.com/PopsiCola/SSM-mybatis/tree/association_lazy
欢迎star