一级缓存
1.一级缓存的作用域是SqlSession范围内的,mybatis默认开启一级缓存,无需任何配置。
2.当在同一个SqlSession中执行多次相同的sql语句,第一次执行完毕会将查询的数据写到缓存中,之后的查询直接从缓存中获取数据,不用去底层数据库查询。
3.如果SqlSession执行了DML操作(insert、update和delete),并提交到数据库,则一级缓存会被清空,以保证缓存中的数据是最新的。
二级缓存
1.二级缓存是mapper级别的缓存(mapper.xml的同一个namespace),可以被多个SqlSession共享。
2.开启二级缓存只需要在相应的xxxMapper.xml加入cache标签即可(因为二级缓存的总开关默认是开启的,我们就可以不再配置了)
3.二级缓存可自定义,实现了Cache接口的类都可以作为二级缓存,所以我们可以使用redis等第三方缓存数据库
4.自定义二级缓存(redis为例):
实现Cache接口,重写相应的方法,在相应的mapper文件中加入
<cache type="com.ywj.cache.MybatisRedisCache"></cache> type的值为具体的全类名
注意事项:
1. 在MyBatis中标签中有flushCache、useCache这两个配置属性
如果属性是在select标签中设置:
flushCache默认为false,表示任何时候此标签中的sql语句被调用,都不会去清空本地缓存和二级缓存。
useCache默认为true,表示会将本条语句的查询结果进行二级缓存。
如果属性是在insert、update、delete标签中设置
flushCache默认为true,表示任何时候语句被调用,都会导致本地缓存和二级缓存被清空。
useCache属性在该情况下不存在。
2. 关于是否禁用懒加载,这里测试了不关闭懒加载也没有问题
<settings>
<!-- 禁用懒加载 -->
<setting name="lazyLoadingEnabled" value="false" />
</settings>
3.要想使二级缓存生效,查询语句后需要用SqlSession对象需要调用commit()或close()【这里当时踩坑了..不提交的话,缓存就没有写入】
进行select操作后,调用SqlSession.close()方法,会将其一级缓存的数据放进二级缓存中,此时一级缓存随着SqlSession的关闭也就不存在了。
进行select操作后,调用SqlSession.commit()方法,会将其一级缓存的数据放进二级缓存中,并清空一级缓存。
5.cache标签属性详解:
1.flushInterval:刷新间隔,刷新缓存即清空缓存。默认没有刷新间隔,当执行增删改时刷新缓存。
2.size:缓存数目,就是最多缓存地对象数。默认值1024
3.readOnly:只读,默认false
4.eviction:收回策略。默认LRU,有如下几种:
1.LRU:最近最少使用的策略,移除最长时间不被使用的对象。
2.FIFO:先进先出策略,按对象进入缓存的顺序来移除它们。
3.SOFT:软引用策略,移除基于垃圾回收器状态和软引用规则的对象。
4.WEAK:弱引用策略,更积极地移除基于垃圾回收器状态和软引用规则的对象。
5.type:使用自定义缓存,默认使用mybatis内置地二级缓存
自定义二级缓存
public class MybatisRedisCache implements Cache{
private String id;
public MybatisRedisCache(String id) {
this.id = id;
}
/**
* 清空缓存
*/
@Override
public void clear() {
JedisUtils.clear();
}
/**
* 获取缓存对象的唯一标识
*/
@Override
public String getId() {
return this.id;
}
/**
* 从缓存对象中获取key对应的value
*/
@Override
public Object getObject(Object key) {
return JedisUtils.get(key);
}
/**
* 获取读写锁
* 可选的方法,从3.2.6起这个方法不再被框架核心调用
* 任何需要的锁,都必须由缓存供应商提供
*/
@Override
public ReadWriteLock getReadWriteLock() {
return null;
}
/**
* 获取缓存对象中存储的键/值对的数量
* 可选的方法,没有被框架核心调用
*/
@Override
public int getSize() {
return JedisUtils.getSize();
}
/**
* 保存key/value到缓存对象中
* key可以是任何对象
*/
@Override
public void putObject(Object key, Object value) {
JedisUtils.set(key, value);
}
/**
* 可选的方法,没有被核心框架调用,移除key对应的value
*/
@Override
public Object removeObject(Object key) {
return null;
}
/**
* 重写equals方法
*/
@Override
public boolean equals(Object o) {
if (getId() == null)
throw new CacheException("Cache instances require an ID.");
if (this == o)
return true;
if (!(o instanceof Cache))
return false;
Cache otherCache = (Cache) o;
return getId().equals(otherCache.getId());
}
/**
* 重写hashCode方法
*/
@Override
public int hashCode() {
if (getId() == null)
throw new CacheException("Cache instances require an ID.");
return getId().hashCode();
}
}