1、什么是缓存:存在内存中的临时数据
将用户经常查询的数据放在缓存(内存)中,用户去查询数据就不用从磁盘(关系数据库数据文件)查询,从缓存中查询,从而提高查询效率,解决高并发系统的性能问题。
2、为什么使用缓存
减少和数据库的交互次数,减少系统开销,提高系统效率
3、什么样的数据能使用缓存
经常查询并且不经常改变的数据
Mybatis缓存
mybatis系统中默认定义了两级缓存:一级缓存和二级缓存
默认情况下,只有一级缓存开启。(SqlSession级别的缓存,也称为本地缓存)
二级缓存需要手动开启和配置,他是基于namespace级别的缓存
Mybatis定义了缓存接口Cache.我们可以通过实现Cache接口来自定义耳机缓存
一级缓存
一级缓存默认是开启的在sqlSession被创建到sqlSession.close(也就是sqlSession创建到关闭)
在同一个sqlSession中查询同一个数据就是从缓存中拿到的数据
public class Test1 {
@Test
public void test2(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
User user1 = mapper.queryUserById(1);
System.out.println(user1);
System.out.println("========================");
User user2 = mapper.queryUserById(1);
System.out.println(user2);
sqlSession.close();
}
}
从日志可以看到,只执行了一次sql语句
缓存失效的情况:
1、查询不同的数据,缓存会失效
public class Test1 {
@Test
public void test2(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
User user1 = mapper.queryUserById(1);
System.out.println(user1);
System.out.println("========================");
User user2 = mapper.queryUserById(2);
System.out.println(user2);
sqlSession.close();
}
}
2、增删改操作,可能会改变原来的数据,所以必定会刷新缓存!
public class Test1 {
@Test
public void test2(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
int i = mapper.updateUser(new User(1, "张三", ""));
if(i > 0){
sqlSession.commit();
System.out.println("修改成功");
}
User user1 = mapper.queryUserById(1);
System.out.println(user1);
System.out.println("========================");
User user2 = mapper.queryUserById(1);
System.out.println(user2);
System.out.println("========================");
sqlSession.close();
}
}
3、查询不同的Mapper.xml
4、手动清理缓存
public class Test1 {
@Test
public void test2(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
User user1 = mapper.queryUserById(1);
System.out.println(user1);
//手动清理缓存
sqlSession.clearCache();
System.out.println("========================");
User user2 = mapper.queryUserById(1);
System.out.println(user2);
System.out.println("========================");
sqlSession.close();
}
}
二级缓存
二级缓存也叫全局缓存,一级缓存的作用域太低了。所以诞生了二级缓存
基于namespsce级别的缓存,一个名称空间,对应一个二级缓存;
工作机制:一个绘画查询一条数据,这个数据就会被放在一级缓存中。
如果当前会话关闭了,这个会话对应的一级缓存就没有了,会话关闭后,一级缓存的数据被保存到二级缓存中;
新的会话查询信息,就可以从二级缓存中获取内容;
不同的mapper查出的数据会放在自己对应的缓存(map)中
步骤:
1、开启全局缓存
在配置文件settings标签中开启全局缓存
<setting name= "cacheEnabled" value="true" />
2、二级缓存只需要在sql映射文件中添加一行
<cache/>
也可以定义一些功能,看官网的具体介绍
3、测试
没有开启二级缓存时
public class Test1 {
@Test
public void test2(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
User user1 = mapper.queryUserById(1);
System.out.println(user1);
sqlSession.close();
System.out.println("========================");
SqlSession sqlSession2 = MybatisUtils.getSqlSession();
UserMapper mapper2 = sqlSession2.getMapper(UserMapper.class);
User user2 = mapper2.queryUserById(1);
System.out.println(user2);
System.out.println("========================");
sqlSession2.close();
}
}
可以看到sql执行了两次
开启二级缓存后,只执行了一次sql
存在的问题,没有设置策略的时候,就是只使用<cache/>标签时需要注意 要将实体类序列化
否则就会报错
org.apache.ibatis.cache.CacheException: Error serializing object. Cause: java.io.NotSerializableException: com.li.pojo.User
序列化实体类
总结:只要开启了二级缓存,缓存在同一个Mapper下就有效
所有的数据都会先放在一级缓存中
只有当会话提交,或者关闭的时候才会到二级缓存中
缓存的原理
用户执行查询之后
先在二级缓存中找看能不能找到
二级缓存没有再到一级缓存中找
一级缓存也没有最后走数据库
自定义缓存
网上去找一下配置文件就行