mybatis会将查询出来的数据存放到缓存中,当再次查询重复数据时,直接从缓存中取出,避免重复查询相同数据而浪费系统资源
mybatis缓存分为:一级缓存 、二级缓存
- 一级缓存 (作用域比较小)
一级缓存:本地缓存(sqlSession级别缓存),与数据库同一次会话(sqlSession)期间查询到的数据会被放到本地缓存中,如果直接从缓存中获取,不会再次向数据库查询数据
mybatis一直默认开启一级缓存,不同的sqlSession级别缓存,数据不可共用
一级缓存失效情况(没有使用到当前一级缓存的情况,如果没有使用,效果就是第二次查询相同语句还需要向数据库发送sql)
失效情况:
1.sqlSession不同
2.当sqlSession对象相同,查询条件不同,原因第一次查询的过程中一级缓存中没有第二次查询需要的数据
3.当sqlSession对象相同,两次查询之间进行了增删改查的操作
4.当sqlSession对象相同,手动清除了一级缓存中的数据
- 二级缓存 (全局缓存) 基于namespace(就是sql的mapper.xml文件)级别的缓存
1.一个会话查询出一条数据,这个数据会被放到当前会话的一级缓存中,如果会话没有关闭,第二次再查询,直接从一级缓存中取出
2.如果当前会话被关闭掉,那么对应的一级缓存没有了,但是mybatis会将一级缓存数据保存到二级缓存中,如果再次创建一次会话,在重新发送查询,返回的数据可以直接从第二级缓存中进行获取
二级缓存是基于一级缓存的
使用二级缓存
1.在mybatis全局配置文件中配置: setting标签下 --->> <setting name="cacheEnabled" value="true"/>
<settings>
<!-- 开启二级缓存: 如果设置为false二级缓存被关闭,一级缓存依然可以使用 -->
<setting name="cacheEnabled" value="true"/>
</settings>
2.在mapper.xml中配置使用二级缓存 <cache>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.mybatis.mapper.EmployeeMapper">
<cache eviction="FIFO" flushInterval="60000" readOnly="false" size="1024">
<!--
cache 标签用于开启二级缓存策略
属性:
eviction 缓存的回收策略 属性值: LRU(回收很少使用的对象) FIFO(对象先进先出)
flushInterval 刷新缓存间隔,配置毫秒数,默认不清空
size 缓存的引用数目 (设置任意正整数 默认1024)
readOnly 是否只读 设置true代表只读 false不是只读
type:使用第三方缓存方案创建适配器,来完全覆盖缓存行为
-->
</cache>
......................省略
</mapper>
3.bean实体类要实现Serializable接口(序列化) 二级缓存内部是基于序列化的
public class Employee implements Serializable {
private static final long serialVersionUID = 1L;
//........................
}
有关于二级缓存之 SQL的 mapper.xml 文件配置属性:
1. select 标签属性:useCache="true" 默认为true ,代表缓存都可以使用
2. nsert update delete 标签中有一个默认属性:flushCache(代表执行完之后清空缓存数据)
查询过程: 二级缓存 -->> 一级缓存 -->> 数据库
会话查询数据之后,会把数据先存放到自己的一级缓存中,如果会话关闭,会把数据存放到二级缓存中。
第二次查询先看二级缓存中有没有对应的,如果二级缓存中没有,就去一级缓存中找,
如果一级缓存也没有,则重新向数据库发送语句进行查找
ps:
在两次查询之间进行新增修改删除的任意一个操作,对一级缓存和二级缓存都会影响
原因是在mapper文件中的insert update delete 默认有一个属性:flushCache=“true” 表示清空缓存
例:
class Test{
public static void main(String[] args) throws IOException {
String resource = "mybatis_config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//每一个sqlSession对象都拥有自己的缓存
SqlSession session1 = sqlSessionFactory.openSession();
SqlSession session2 = sqlSessionFactory.openSession();
//利用反射创建employee的持久层实现类
EmployeeMapper mapper1 = session1.getMapper(EmployeeMapper.class);
EmployeeMapper mapper2 = session2.getMapper(EmployeeMapper.class);
Employee emp1 = mapper1.findEmpById(3);
System.out.println("emp1=========="+emp1);
/*
* 关闭Session1
* 关闭之后,该session中一级缓存的数据将被mybatis保存到二级缓存中
*/
session1.close();
//查询同样的数据,从二级缓存中取出
Employee emp2 = mapper2.findEmpById(3);
System.out.println("emp2=========="+emp2);
} }