Mybatis学习笔记(六):一级缓存、二级缓存

13.1、简介

1.什么是缓存(cache)?

  • 存在内存中的临时数据
  • 将用户经常查询的数据放在缓存(内存)中,用户查询该数据的时候就不用从磁盘上(关系型数据库数据文件)查询,在缓存的数据计算机可以直接拿到,从而提高查询效率,解决了高并发系统的性能问题

2.为什么使用缓存?

  • 减少和数据库的交互次数,减少系统开销,提高系统效率

3.什么样的数据能使用缓存

  • 经常查询且不经常该表的数据

13.2、MyBatis缓存

  • MyBatis 内置了一个强大的事务性查询缓存机制,它可以非常方便地配置和定制。缓存可以极大的提升查询效率。
  • MyBatis系统中默认定义了两级缓存:一级缓存、二级缓存
    • 默认情况下,只启用了一级缓存。(sqlSession级别的缓存,也称为本地缓存)
    • 要启用全局的二级缓存,需要手动开启和配置,他是基于namespace级别的缓存
    • 为了提高扩展性,Mybatis定义了缓存接口Cache,我们可以通过实现Chche接口来自定义二级缓存

13.3、一级缓存

  • 一级缓存,也称为本地缓存:
    • 与数据库同义词会话期间查询到的shu’j会放在本地缓存中。
    • 这期间如果需要获取相同的数据,直接从缓存中拿,没必要再去查询数据库

mybatis默认开启一级缓存,只在sqlseesion中有效,也就是连接到关闭这个链接区间段。

一级缓存就是一个map

测试查看一级缓存

1.开启日志,方便查看缓存调用的情况。

2.测试在一个sqlSession中查询两次相同的记录

SqlSession sqlSession = MybatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
User user = mapper.queryUserById(1);
System.out.println(user);
System.out.println("==========第二次查询============");
User user2 = mapper.queryUserById(1);
System.out.println(user2);
System.out.println(user==user2);
sqlSession.close();

查看日志输出

在这里插入图片描述

可以看出,在一次会话中,第二次查询相同的数据,是被直接从缓存中拿出来的并没有再次去调用数据库,这是因为mybatis默认开启一级缓存。

缓存失效的情况

  • 映射语句文件中的所有 insert、update 和 delete 语句会刷新缓存。测试:

(在上面的语句中加入更新用户的语句)

...
//执行一次修改
mapper.updateUser(new User(2, "ooooo", "ppppp"));
System.out.println("==========第二次查询============");
...

查看日志
在这里插入图片描述

因为增删改操作,可能会改变原来的数据,所以必定会刷新缓存

  • 查询不同的东西

在这里插入图片描述

因为查询了之前没有查询过的,需要去再次访问数据库,将其放到缓存中。

  • 查询不同的Mapper.xml
  • 手动清理缓存
...
sqlSession.clearCache();//手动清理缓存
System.out.println("==========第二次查询============");
...

查看日志,可以看出第二次因为缓存被清理了是去数据库查询,并没有访问到缓存。

在这里插入图片描述

比如同一个用户在不断的刷新页面,这时候就展现了一级缓存的用处。

如果是不同的用户来访问相同的数据,那么一级缓存就失效了,这个时候就需要二级缓存。

13.4、二级缓存

  • 二级缓存也叫全局缓存,一级缓存作用域太低了,所以诞生了二级缓存。
  • 基于namespace级别的缓存,一个名称空间,对应一个二级缓存;
  • 工作机制
    • 一个会话查询一条数据,这个数据就会被放在当前会话的一级缓存中
    • 如果当前会话关闭了,这个会话的一级缓存就消失了;但是我们需要的是,会话关闭了,一级缓存中的数据保留在二级缓存中。(再关闭的时候,把缓存“遗传”下来)
    • 新的查询信息,就可以在二级缓存中获取。
    • 不同mapper查出的数据就会放在自己对应的缓存(map)中。

步骤:

1.开启全局缓存,默认虽然是true,但是最好我们能显式的把它写出来。增强可读性。

<!--显式的开启全局缓存-->
<setting name="cacheEnabled" value="true"/>

2.要启用全局的二级缓存,只需要在你的 SQL 映射文件(Mapper.xml)中添加一行:

<cache/>

也可以自定义参数

<cache
  eviction="FIFO"
  flushInterval="60000"
  size="512"
  readOnly="true"/>

这个更高级的配置创建了一个 FIFO 缓存,每隔 60 秒刷新,最多可以存储结果对象或列表的 512 个引用,而且返回的对象被认为是只读的,因此对它们进行修改可能会在不同线程中的调用者产生冲突。

测试:

1.创建两个sqlSession,模拟两个用户来查同一个数据。

//用户1
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
User user = mapper.queryUserById(1);
System.out.println(user);
sqlSession.close();

//用户2
SqlSession sqlSession2 = MybatisUtils.getSqlSession();
UserMapper mapper2 = sqlSession2.getMapper(UserMapper.class);
User user2 = mapper2.queryUserById(1);
System.out.println(user2);
sqlSession2.close();

查看日志,一级缓存查询了两次。

在这里插入图片描述

2.按上面的方式,开启二级缓存。再查

//用户1
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
User user = mapper.queryUserById(1);
System.out.println(user);
sqlSession.close();

//用户2
SqlSession sqlSession2 = MybatisUtils.getSqlSession();
UserMapper mapper2 = sqlSession2.getMapper(UserMapper.class);
User user2 = mapper2.queryUserById(1);
System.out.println(user2);
sqlSession2.close();

查看日志
在这里插入图片描述

发现第二次查询,只查了一次,第二次是从缓存中拿。

再强点一次,是需要在同一个mapper里面才有二级缓存。

总结:

1.我们需要将实体类序列化。否则会报错

Caused by: java.io.NotSerializableException: com.yong.pojo.User

在实体类中实现序列化的接口

public class User implements Serializable{

}

2.只要开启了二级缓存,在同一个mapper下有效

3.所有的而数据都会先放在一级缓存中,当会话提交或者会话关闭的时候,才会提交到二级缓存中,

缓存顺序

1.第一次查询先看二级缓存中有没有

2.再看一级缓存中有没有

3.最后查询数据库。

查询数据库,会保存在一级缓存中(使用Map),然后当会话结束或者会话提交的时候保存到二级缓存中。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值