碰见了不懂,学学接着
还是提问:首先,什么是缓存?
缓存其实就是存储在内存中的临时数据,这里的数据量会比较小,一般来说,服务器的内存也是有限的,不可能将所有的数据都放到服务器的内存里面,所以, 只会把关键数据放到缓存中,缓存因为速度快,使用方便而广泛使用
缓存在数据库中对查询结果的保存,可以使用缓存,这样能减少跟数据库交互的次数,进而提高响应速度。
Mybatis也提供了对缓存的支持,分为一级缓存和二级缓存,可以通过下图和下表来理解:
一级缓存是默认开启的,它在一个sqlSession会话里面的所有查询操作都会保存到缓存中,一般来说一个请求中的所有增删改查操作都是在同一个sqlSession里面的,所以我们可以认为每个请求都有自己的一级缓存,如果同一个sqlSession会话中2 个查询中间有一个 insert 、update或delete 语句,那么之前查询的所有缓存都会清空。
例如下面Mybatis的代码:
代码中所走的所有查询操作都会进行默认进行一级缓存,一旦关闭sqlSession会话,缓存则会刷新
//1.加载核心配置文件
InputStream is = Resources.getResourceAsStream("MyBatisConfig.xml");
//2.获取SqlSession工厂对象
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
//3.通过工厂对象获取SqlSession对象
SqlSession sqlSession = sqlSessionFactory.openSession(true);
//4.获取StudentMapper接口的实现类对象
StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
//5.调用实现类对象中的方法,接收结果
Student stu = new Student(4,"赵六",36);
Integer result = mapper.update(stu);
// 这中间所走的所有查询操作都会进行缓存,一旦关闭sqlSession会话,缓存则会刷新
//6.处理结果
System.out.println(result);
//7.释放资源
// 清除缓存
sqlSession.clearCache();
// 释放会话
sqlSession.close();
// 关闭流
is.close();
这样看也是不明显的,我们在mybatis 的配置文件中加入以下配置,开启sql日志,每一个sql代表请求了一次数据库,这样我们就可以根据sql来判断是否使用了缓存。
<settings>
<setting name="logImpl" value="STDOUT_LOGGING"/>
settings>
或者配置log4j输出日志
<settings>
<setting name="logImpl" value="log4j"/>
settings>
我们查询两次:
//5.调用实现类对象中的方法,接收结果
Student stu = new Student(4,"赵六",36);
Integer result = mapper.update(stu);
System.out.println(stu);
Student stu2 = new Student(4,"赵六",36);
System.out.println(stu2);
我们可以看到控制台其实就执行了一次sql代码:
说明他默认一级缓存了
一级缓存无过期时间,只有生命周期
MyBatis在开启一个数据库会话时,会创建一个新的SqlSession对象,SqlSession对象中会有一个Executor对象,Executor对象中持有一个PerpetualCache对象,当会话结束时,SqlSession对象及其内部的Executor对象还有PerpetualCache对象也一并释放掉。
二级缓存是全局的,也就是说;多个请求可以共用一个缓存,二级缓存需要手动开启,有2种方式配置二级缓存,缓存会先放在一级缓存中,当sqlSession会话提交或者关闭时才会将一级缓存刷新到二级缓存中;
开启二级缓存后,用户查询时,会先去二级缓存中找,找不到在去一级缓存中找;
如下图二级缓存的工作原理图
在关闭sqlsession后(close),才会把该sqlsession一级缓存中的数据添加到namespace的二级缓存中。
注意:开启了二级缓存后,建议将要缓存的pojo实现Serializable接口,为了将缓存数据取出执行反序列化操作,因为二级缓存数据存储介质多种多样,不一定只存在内存中,有可能存在硬盘中。
单个mapper配置,主需要在需要开启二级缓存的mapper.xml文件中加入以下配置即可开启。
<cache />
注意一定要加到xxMapper.xml的文件内,千万不要加到mybatis 的主配置文件里面了,会报错的,正确的配置位置如下图所示:
所有的mapper都开启二级缓存,在mybatis.xml中加入以下配置即可
<settings>
<setting name="logImpl" value="log4j"/>
<setting name="cacheEnabled" value="true"/>
settings>
二级缓存的过期时间是这个cache的过期时间,是flushInterval,意味着整个清空缓存cache,所以不需要后台线程去定时检测。
每当存取数据的时候,都有检测一下cache的生命时间,默认是1小时,如果这个cache存活了一个小时,那么将整个清空一下。
另外,缓存还有以下几种情况需要注意
映射语句文件中的所有 select 语句的结果将会被缓存。
映射语句文件中的所有 insert、update 和 delete 语句会刷新缓存。
缓存会使用最近最少使用算法(LRU, Least Recently Used)算法来清除不需要的缓存。
缓存不会定时进行刷新(也就是说,没有刷新间隔)。
缓存会保存列表或对象(无论查询方法返回哪种)的 1024 个引用。
缓存会被视为读/写缓存,这意味着获取到的对象并不是共享的,可以安全地被调用者修改,而不干扰其他调用者或线程所做的潜在修改。