MyBatis缓存
MyBatis一级缓存
- 一级缓存是SqlSession级别的,通过同一个SqlSession查询的数据会被缓存,下次查询相同的数据,就会从缓存中直接获取,不会去访问数据库
- 一级缓存失效的四种情况
- 不同的SqlSession对应不同的一级缓存
- 同一个SqlSession但查询条件不同
- 同一个SqlSession两次查询期间执行了任何一次增删改操作
- 同一个SqlSession两次查询期间手动清除了缓存
@Test
public void testGetEmp() {
SqlSession sqlSession1 = SqlSessionUtils.getSqlSession();
CacheMapper mapper1 = sqlSession1.getMapper(CacheMapper.class);
Emp emp1 = mapper1.getEmpById(4);
System.out.println(emp1);
sqlSession1.clearCache();
Emp emp2 = mapper1.getEmpById(4);
System.out.println(emp2);
mapper1.insertEmp(new Emp(null,"jack",23,"男","jack@qq.com"));
CacheMapper mapper2 = sqlSession1.getMapper(CacheMapper.class);
Emp emp3 = mapper2.getEmpById(4);
System.out.println(emp3);
SqlSession sqlSession2 = SqlSessionUtils.getSqlSession();
CacheMapper mapper3 = sqlSession2.getMapper(CacheMapper.class);
Emp emp4 = mapper3.getEmpById(4);
System.out.println(emp4);
}
DEBUG 06-14 14:45:16,001 ==> Preparing: select * from t_emp where eid=? (BaseJdbcLogger.java:137)
DEBUG 06-14 14:45:16,021 ==> Parameters: 4(Integer) (BaseJdbcLogger.java:137)
DEBUG 06-14 14:45:16,048 <== Total: 1 (BaseJdbcLogger.java:137)
Emp{eid=4, empName='tye', age=14, sex='男', email='tye@qq.com', dept=null}
DEBUG 06-14 14:45:16,048 ==> Preparing: select * from t_emp where eid=? (BaseJdbcLogger.java:137)
DEBUG 06-14 14:45:16,048 ==> Parameters: 4(Integer) (BaseJdbcLogger.java:137)
DEBUG 06-14 14:45:16,048 <== Total: 1 (BaseJdbcLogger.java:137)
Emp{eid=4, empName='tye', age=14, sex='男', email='tye@qq.com', dept=null}
DEBUG 06-14 14:45:16,048 ==> Preparing: insert into t_emp(eid,emp_name,age,sex,email) values(null,?,?,?,?); (BaseJdbcLogger.java:137)
DEBUG 06-14 14:45:16,048 ==> Parameters: jack(String), 23(Integer), 男(String), jack@qq.com(String) (BaseJdbcLogger.java:137)
DEBUG 06-14 14:45:16,056 <== Updates: 1 (BaseJdbcLogger.java:137)
DEBUG 06-14 14:45:16,056 ==> Preparing: select * from t_emp where eid=? (BaseJdbcLogger.java:137)
DEBUG 06-14 14:45:16,056 ==> Parameters: 4(Integer) (BaseJdbcLogger.java:137)
DEBUG 06-14 14:45:16,056 <== Total: 1 (BaseJdbcLogger.java:137)
Emp{eid=4, empName='tye', age=14, sex='男', email='tye@qq.com', dept=null}
DEBUG 06-14 14:45:16,111 ==> Preparing: select * from t_emp where eid=? (BaseJdbcLogger.java:137)
DEBUG 06-14 14:45:16,111 ==> Parameters: 4(Integer) (BaseJdbcLogger.java:137)
DEBUG 06-14 14:45:16,127 <== Total: 1 (BaseJdbcLogger.java:137)
Emp{eid=4, empName='tye', age=14, sex='男', email='tye@qq.com', dept=null}
MyBatis二级缓存
- 二级缓存是SqlSessionFactory级别,通过同一个SqlSessionFactory创建的SqlSession查询的结果会被缓存,此后再执行相同查询,结果就会从缓存中获取
- 二级缓存开启条件:
- 在核心配置文件中,设置全局配置属性cacheEnabled=“true”,默认为true,不需要设置
- 在映射文件中设置标签
- 二级缓存必须在SqlSession关闭或提交之后有效
- 查询的数据所转换的实体类型必须实现序列化的接口
@Test
public void testTwoCache() throws IOException {
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(is);
SqlSession sqlSession1 = sqlSessionFactory.openSession(true);
CacheMapper mapper1 = sqlSession1.getMapper(CacheMapper.class);
System.out.println(mapper1.getEmpById(4));
sqlSession1.close();
SqlSession sqlSession2 = sqlSessionFactory.openSession(true);
CacheMapper mapper2 = sqlSession2.getMapper(CacheMapper.class);
System.out.println(mapper2.getEmpById(4));
sqlSession2.close();
}
DEBUG 06-14 15:23:18,059 Cache Hit Ratio [com.lotus.mybatis.mapper.CacheMapper]: 0.0 (LoggingCache.java:60)
DEBUG 06-14 15:23:18,968 ==> Preparing: select * from t_emp where eid=? (BaseJdbcLogger.java:137)
DEBUG 06-14 15:23:18,984 ==> Parameters: 4(Integer) (BaseJdbcLogger.java:137)
DEBUG 06-14 15:23:19,015 <== Total: 1 (BaseJdbcLogger.java:137)
Emp{eid=4, empName='tye', age=14, sex='男', email='tye@qq.com', dept=null}
WARN 06-14 15:23:19,015 As you are using functionality that deserializes object streams, it is recommended to define the JEP-290 serial filter. Please refer to https://docs.oracle.com/pls/topic/lookup?ctx=javase15&id=GUID-8296D8E8-2B93-4B9A-856E-0A65AF9B8C66 (SerialFilterChecker.java:46)
DEBUG 06-14 15:23:19,015 Cache Hit Ratio [com.lotus.mybatis.mapper.CacheMapper]: 0.5 (LoggingCache.java:60)
Emp{eid=4, empName='tye', age=14, sex='男', email='tye@qq.com', dept=null}
- 二级缓存失效情况
- 两次查询期间执行了任何一次增删改操作,会使一级和二级缓存同时失效
二级缓存相关配置
- 在mapper配置文件中添加的cache标签可以设置一些属性
- eviction属性:缓存回收策略
- LRU(Least Recently Used) :最近最少使用,移除最长时间不被使用的对象
- FIFO(First In First Out):先进先出,按对象进入缓存的顺序来移除它们
- SOFT:软引用,移除基于垃圾回收器状态和软引用规则的对象
- WEAK:弱引用,更积极地移除基于垃圾收集器状态和弱引用规则的对象
- 默认LRU
- flushInterval属性:刷新间隔,单位毫秒
- 默认不设置,也就是无刷新间隔,缓存仅调用语句时刷新
- size属性:引用数目,正整数
- 代表缓存最多可以存储多少个对象,太大容易导致内存溢出
- readOnly属性:只读,true|false
- true:只读缓存,会给所有调用者返回缓存对象的相同实例,因此这些对象不能被修改,提供了很重要的性能优势
- false:读写缓存,会返回缓存对象的拷贝(通过序列化),会慢一些,但安全,默认为false
缓存查询顺序
- ①先查询二级缓存,二级缓存中可能会有其他程序已经查出来的数据,可以拿来直接使用
- ②如果二级缓存没有命中,再查询一级缓存
- ③如果一级缓存也没有命中,则查询数据库
- ④SqlSession关闭之后,一级缓存中的数据会导入二级缓存
整合第三方缓存EHCache
<dependency>
<groupId>org.mybatis.caches</groupId>
<artifactId>mybatis-ehcache</artifactId>
<version>1.2.1</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
</dependency>