Mybatis中的延迟加载
延迟加载的引入
引入问题:在一对多中,当我们有一个用户,它有100个账户。
- 在查询用户的时候要不要把所有的账户都查询出来?
- 在查询账户的时候,要不要把关联的用户查出来?
- 在查询用户时,用户下的账户信息应当是,什么时候用,什么时候查询出来
- 在查询账户时,账户所属的用户信息应当是随着账户查询时一起查询出来
什么是延迟加载?
在真正使用数据时,才发起查询。按需加载(懒加载)
什么是立即加载?
不管有没有使用到,只要一调用方法,马上发起查询
在对应的四种表关系中:一对多,多对一,一对一,多对多
一对多、多对多 : 一般采取延迟加载
一对一、多对一 : 一般采用立即加载
开启延迟加载
在主配置文件SqlMapConfig.xml中1
2
3
4
5
6
7<!--配置参数-->
<settings>
<!--开启Mybatis延迟加载的全局开关-->
<setting name="lazyLoadingEnabled" value="true"/>
<!--每个属性都会按需加载 可以不配 默认值就是false-->
<setting name="aggressiveLazyLoading" value="false"></setting>
</settings>
在AccountMapper.xml中1
2
3
4
5
6
7
8
9
10
11<resultMap id="accountUserMap" type="account">
<id property="id" column="id"></id>
<result property="uid" column="uid"></result>
<result property="money" column="money"></result>
<!--1对1关系映射,配置封装user内容 column设置为从表中的外键-->
<association property="user" column="uid" javaType="user" select="com.xushui.dao.UserMapper.findById"></association>
</resultMap>
<select id="findAll" resultMap="accountUserMap" >
select * from account a
</select>
在UserMapper.xml中1
2
3<select id="findById" parameterType="Integer" resultType="User">
select * from user where id = #{id}
</select>
当只执行,不需要用到用户信息时,使用了延迟加载1
2
3
4@Test
public void testFindAll() {
List<Account> accounts = accountMapper.findAll();
}
在日志信息中可以看到1
2
32019-07-31 10:34:20,357 723 [ main] DEBUG shui.dao.AccountMapper.findAll - ==> Preparing: select * from account a
2019-07-31 10:34:20,392 758 [ main] DEBUG shui.dao.AccountMapper.findAll - ==> Parameters:
2019-07-31 10:34:20,477 843 [ main] DEBUG shui.dao.AccountMapper.findAll - <== Total: 3
若需要用户信息时1
2
3
4
5
6
7
8@Test
public void testFindAll() {
List<Account> accounts = accountMapper.findAll();
for (Account account : accounts) {
System.out.println(account);
System.out.println(account.getUser());
}
}
在日志中可以看到对用户信息发起了查询1
2
3
4
5
6
7
8
9
10
11
12
13
14
152019-07-31 10:44:13,182 635 [ main] DEBUG shui.dao.AccountMapper.findAll - ==> Preparing: select * from account a
2019-07-31 10:44:13,229 682 [ main] DEBUG shui.dao.AccountMapper.findAll - ==> Parameters:
2019-07-31 10:44:13,285 738 [ main] DEBUG shui.dao.AccountMapper.findAll - <== Total: 3
2019-07-31 10:44:13,286 739 [ main] DEBUG xushui.dao.UserMapper.findById - ==> Preparing: select * from user where id = ?
2019-07-31 10:44:13,286 739 [ main] DEBUG xushui.dao.UserMapper.findById - ==> Parameters: 41(Integer)
2019-07-31 10:44:13,295 748 [ main] DEBUG xushui.dao.UserMapper.findById - <== Total: 1
Account{id=1, uid=41, money=1000.0}
User{id=41, username='老王', birthday=Tue Feb 27 17:47:08 CST 2018, sex='男', address='北京'}
2019-07-31 10:44:13,295 748 [ main] DEBUG xushui.dao.UserMapper.findById - ==> Preparing: select * from user where id = ?
2019-07-31 10:44:13,295 748 [ main] DEBUG xushui.dao.UserMapper.findById - ==> Parameters: 45(Integer)
2019-07-31 10:44:13,297 750 [ main] DEBUG xushui.dao.UserMapper.findById - <== Total: 1
Account{id=2, uid=45, money=1000.0}
User{id=45, username='传智播客', birthday=Sun Mar 04 12:04:06 CST 2018, sex='男', address='北京金燕龙'}
Account{id=3, uid=41, money=2000.0}
User{id=41, username='老王', birthday=Tue Feb 27 17:47:08 CST 2018, sex='男', address='北京'}
Mybatis中的缓存
什么是缓存?
存在内存中的临时数据,比如说在第一次查询之后,就将其存储在内存,下一次要使用时,就不需要再去数据库查询,减少与数据库交互的次数,从而提高执行效率。
为什么使用缓存?
减少和数据库交互次数,提高执行效率。
什么样的数据能使用缓存,什么样的数据不能使用?
- 适用于缓存
- 使用频率高的数据
- 不经常改变的数据
- 数据的正确与否对最终效果影响不大的数据
- 不适用缓存的
- 经常改变的数据
- 数据的正确与否对最终结果影响很大的数据
- 例:商品的库存,银行的汇率,股市的牌价
Mybatis中的一级缓存和二级缓存
一级缓存
- 它指的是Mybatis中SqlSession对象的缓存
- 当我们执行查询之后,查询结果会同时存入到SqlSession为我们提供的一片区域中
- 结构是一种Map,当我们再次查询同样的数据,Mybatis会先从SqlSession中查询是否有,有的话就可以直接使用
- 当Sqlsession对象消失时,mybatis中的一级缓存就消失了
示范:1
2
3
4
5
6
7
8@Test
public void testFirstCache(){
User user1 = userMapper.findById(41);
System.out.println(user1);
User user2 = userMapper.findById(41);
System.out.println(user2);
System.out.println(user1 == user2);
}
日志中,可以看出只查询了一次,第二次是从缓存中取出。不过必须要确保SqlSession对象是同一个对象,没有消失,如果消失了,或者使用了clearCache()方法,缓存会被清空,就要重新查询。
1 | 2019-07-31 11:44:29,587 607 [ main] DEBUG xushui.dao.UserMapper.findById - ==> Preparing: select * from user where id = ? |
一级缓存的分析
一级缓存是SqlSession范围的缓存,当调用SqlSession的修改,添加,删除,commit(),close()方法时,会清空一级缓存
二级缓存
它指的是Mybatis中SqlSessionFactory对象的缓存,由同一个SqlSessionFactory对象所生产的SqlSession所共享的缓存
二级缓存的使用步骤
让Mybatis框架支持二级缓存(在SqlMapConfig.xml中配置)
1
2
3
4<settings>
<!--全局开启缓存,默认为true-->
<setting name="cacheEnabled" value="true"/>
</settings>让当前的映射文件支持二级缓存(在UserMapper.xml中配置)
1
2<!--开启UserMapper支持二级缓存-->
<cache/>让当前的操作支持二级缓存(在当前操作的标签上配置useCache为true)
1
2
3<select id="findById" parameterType="Integer" resultType="User" useCache="true">
select * from user where id = #{id}
</select>