1. 缓存机制
MyBatis包含一个非常强大的查询缓存特性,它可以非常方便地配置和定制。缓存可以极大的提升查询效率!
mybatis的缓存机制有两级:
- 一级缓存:一级缓存mybatsi已近为我们自动开启,不用我们手动操作,而且我们是关闭不了的!!但是我们可以手动清除缓存。(SqlSession级别,本地缓存)
- 二级缓存:二级缓存需要我们手动开启。(全局级别,全局缓存)
为了提高扩展性。MyBatis定义了缓存接口Cache。我们可以通过实现Cache接口来自定义二级缓存。
1.1. 一级缓存
我们来测试一下:
@Test
public void testCache() throws IOException {
SqlSession sqlSession = getSqlSession();
EmployeeCacheMapper mapper = sqlSession.getMapper(EmployeeCacheMapper.class);
Employee byId = mapper.findById(5);
//2
Employee byId2 = mapper.findById(5);
System.out.println("byId = " + byId);
System.out.println("byId2 = " + byId2);
System.out.println(byId == byId2);
sqlSession.commit();
}
测试结果:
Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@548e6d58]
==> Preparing: select * from employee where id = ?;
==> Parameters: 5(Integer)
<== Columns: id, last_name, email, gender, dept_id
<== Row: 5, Tom, admin1@misiai.com, 男, 1
<== Total: 1
byId = Employee{id=5, lastName='Tom', email='admin1@misiai.com', gender='男', department=null}
byId2 = Employee{id=5, lastName='Tom', email='admin1@misiai.com', gender='男', department=null}
true
结论:
1、SQL语句只打印了一次
2、byId=byId2,也即该对象是同一个。
3、自动开启一级缓存(SqlSession级别)
失效情况:
1、SqlSession不同。
2、SqlSession相同,查询条件不同。
3、SqlSession相同,两次查询之间执行了增删改操作。
4、SqlSession相同,手动清空一级缓存。sqlSession.clearCache();
1.2. 二级缓存
全局缓存,基于namespace的缓存,一个namespace,一个缓存。
工作机制:
1、一个会话,查询一条数据,这个数据就会被放在当前会话的一级缓存中;
2、如果会话关闭;一级缓存中的数据会被保存到二级缓存中;新的会话查询信息,就可以参照二级缓存;
使用:
1、在全局配置文件中,开启:
<settings>
<setting name="cacheEnabled" value="true"/>
</settings>
2、在mapper中开:
<?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.misiai.dao.EmployeeCacheMapper">
<!--cache开启缓存-->
<cache/>
</mapper>
cache属性:
- eviction:缓存的回收策略:
- LRU-最近最少使用的:移除最长时间不被使用的对象。
- FIFO-先进先出:按对象进入缓存的顺序来移除它们。
- SOFT-软引用:移除基于垃圾回收器状态和软引用规则的对象。
- WEAK-弱引用:更积极地移除基于垃圾收集器状态和弱引用规则的对象。
- 默认的是LRU。
- flushInterval:缓存刷新间隔缓存多长时间清空一次,默认不清空,设置一个毫秒值
- readOnly:是否只读;
- true:只读;
- mybatis认为所有从缓存中获取数据的操作都是只读操作,不会修改数据。
- mybatis为了加快获取速度,直接就会将数据在缓存中的引用交给用户。不安全,速度快
- false:非只读;mybatis觉得获取的数据可能会被修改。
- mybatis会利用序列化&反序列的技术克隆一份新的数据给你。安全,速度慢I
- true:只读;
测试
@Test
public void testCache() throws IOException {
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
/*测试二级缓存*/
SqlSession sqlSession = sqlSessionFactory.openSession();
EmployeeCacheMapper mapper = sqlSession.getMapper(EmployeeCacheMapper.class);
SqlSession sqlSession2 = sqlSessionFactory.openSession();
EmployeeCacheMapper mapper2 = sqlSession2.getMapper(EmployeeCacheMapper.class);
//1
Employee byId = mapper.findById(5);
System.out.println("byId = " + byId);
// 这里先必须关闭了,才有缓存。
sqlSession.close();
//2
Employee byId2 = mapper2.findById(5);
System.out.println("byId2 = " + byId2);
sqlSession2.close();
}
细节:
必须是第一次会话关闭后,然后再进行第二次会话查询,才有缓存。
和缓存有关的设置/属性:
1、cacheEnabled=true;false:关闭缓存(二级缓存关闭)(一级缓存一直可用的)
2、每个select标签都有useCache="true";false:不使用缓存(一级缓存依然使用,二级缓存不使用)
3、每个增删改标签的:flushCache="true":增删改执行完成后就会清除缓存;
测试:flushcache="true"一级缓存就清空了;二级缓存也会被清除。
4、sqlSession.clearCache();只是清除当前session的一级缓存;