Mybatis延迟加载和缓存

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
3
2019-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
15
2019-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
2
3
4
5
6
2019-07-31 11:44:29,587 607    [           main] DEBUG xushui.dao.UserMapper.findById  - ==>  Preparing: select * from user where id = ? 
2019-07-31 11:44:29,618 638 [ main] DEBUG xushui.dao.UserMapper.findById - ==> Parameters: 41(Integer)
2019-07-31 11:44:29,647 667 [ main] DEBUG xushui.dao.UserMapper.findById - <== Total: 1
com.xushui.domain.User@e720b71
com.xushui.domain.User@e720b71
true

一级缓存的分析

一级缓存是SqlSession范围的缓存,当调用SqlSession的修改,添加,删除,commit(),close()方法时,会清空一级缓存

二级缓存

它指的是Mybatis中SqlSessionFactory对象的缓存,由同一个SqlSessionFactory对象所生产的SqlSession所共享的缓存

二级缓存的使用步骤

  1. 让Mybatis框架支持二级缓存(在SqlMapConfig.xml中配置)

    1
    2
    3
    4
    <settings>
    <!--全局开启缓存,默认为true-->
    <setting name="cacheEnabled" value="true"/>
    </settings>
  2. 让当前的映射文件支持二级缓存(在UserMapper.xml中配置)

    1
    2
    <!--开启UserMapper支持二级缓存-->
    <cache/>
  3. 让当前的操作支持二级缓存(在当前操作的标签上配置useCache为true)

    1
    2
    3
    <select id="findById" parameterType="Integer" resultType="User" useCache="true">
    select * from user where id = #{id}
    </select>

二级缓存图示


评论

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×