一级缓存(本地缓存)
默认情况下被一直开启,从一个Mapper查询出来后放入本地,一个会话内有效,比如对象01发出一个sql,对象02也是同一个sql,只会发一个sql查询,对象01和02测试相等的时候是true,但是不同的mapper即使查询的语句一样,一级缓存都是会失效的。还有的情况是两次mapper是同一个sql也是同一个,但是中途执行了别的增删改的sql,数据库发生了改变,也会使得对象false
二级缓存(全局缓存)
本次讨论的重点,基于namespace级别
一级缓存的会话被关闭就会保存到二级缓存中
配置
在mybatis配置文件里加入
<!--配置二级缓存-->
<setting name="cacheEnabled" value="true"/>
在需要配置缓存的mapper.xml里配置
【blocking】若缓存中找不到对应的key,是否会一直blocking,直到有对应的数据进入缓存。
【flushInterval】缓存刷新间隔,默认不清空,单位为毫秒值
【eviction】缓存的回收策略
[LRU]默认 最近最少使用,移除最长时间不被使用的对象
[FIFO]-先进先出
[SOFT]-软引用,移除基于垃圾回收器状态和软引用规则的对象
[WEAK]-弱引用,更积极地移除基于垃圾收集器状态和弱引用规则的对象
【readOnly】是否只读[false][true]
【size】缓存存放多少个元素
【type】指定自定义的缓存的全类名,实现过cache接口的类
在指定mapper.xml里(注意这个是模板,如果有的字段是空的,要删掉,不然会报错的。)
<mapper namespace="com.yiki.Dao.PersonMapperDynamicSQL">
<cache blocking=""
flushInterval="60000"
eviction="FIFO"
readOnly="false"
size="1024" type="">
</cache>
POJO对象都要实现序列化接口
public class Person implements Serializable {
private Integer pId;
private String pName;//当和表里的列名不一致的时候,查询语句应该起别名
//p_Name(原表里的列名) pname别名
private String email;
private Department dept;
测试
public void test7() throws IOException {
start();
SqlSession sqlSession1 = sqlSessionFactory.openSession(true);
PersonMapperPlus mapper1 = sqlSession1.getMapper(PersonMapperPlus.class);
Person p1 = mapper1.getPersonById(1);
System.out.println(p1);
sqlSession1.close();
SqlSession sqlSession2 = sqlSessionFactory.openSession(true);
PersonMapperPlus mapper2 = sqlSession2.getMapper(PersonMapperPlus.class);
Person p2 = mapper2.getPersonById(1);
System.out.println(p1);
sqlSession2.close();
System.out.println(p1==p2);
sqlSession.close();
}
只有一条sql
如果不用二级缓存,就会产生两条sql
select标签里的【useCache="true"】
对单个标签里二级缓存有效,注意每个增删改标签里的【flushCache="true"】为默认
并且对一二级缓存都有效,所以每个对数据库的改变后都会重新发送新的sql
其他:
sqlssion.clearCache()对当前会话有效,而对二级缓存无关
localCacheScope本地缓存作用域
-【SESSION】默认,当前会话的所有数据保存在当前会话中
-【STATMENT】可以禁用
其实每个缓存约等于一个Map