Mybatis一级缓存的配置方式:
1 | <setting name="localCacheScope" value="SESSION"/> |
value有两个值可选:
session:缓存对一次会话中所有的执行语句有效,也就是SqlSession级别的。
statement:缓存只对当前执行的这一个Statement有效。
BaseExecutor
一级缓存中对缓存的查询和写入是在Executor中完成的,以BaseExecutor为例,查看query方法:
1 | public abstract class BaseExecutor implements Executor { |
从BaseExecutor的成员变量中,可以看到有一个类型为PerpetualCache变量名为localCache的字段,缓存就是用它来实现的。PerpetualCache类的成员变量也很简单,包含一个id和一个HashMap,缓存数据就存储在HashMap中。
1
2
3
4
5
6
7
8
9public class PerpetualCache implements Cache {
private final String id;
private Map<Object, Object> cache = new HashMap<Object, Object>();//使用一个map做存储
get set方法省略
......
}在BaseExecutor的quey方法中,有一个构建CacheKey的语句,既然缓存数据存储在HashMap中,那么数据格式一定是键值对的形式,这个CacheKey就是HashMap中的key,value是数据库返回的数据。
1
CacheKey key = createCacheKey(ms, parameter, rowBounds, boundSql);
第二个query方法中,当执行查询时,首先通过localCache.getObject(key)从缓存中获取数据,如果获取的数据为空,再从数据库中查找。
1 | //从缓存中获取数据,key的类型为CacheKey |
1 | //如果获取结果为空,从数据库中查找 |
- 如果开启了flushcache,将会清空缓存
1 | //如果queryStack为0或者并且有必要刷新缓存 |
配置flushcache:
1 | <select id="getStudent" parameterType="String" flushCache="true"> |
- 如果一级缓存的级别为Statement,将会清空缓存,这也是如果设置一级缓存的级别为Statement时缓存只对当前执行的这一个Statement有效的原因:
1 | //如果是STATEMENT级别的缓存 |
配置方式:
1 | <setting name="localCacheScope" value="STATEMENT"/> |
CacheKey如何产生的
- 在query方法中,调用了createCacheKey方法生成CacheKey,然后多次调用了cachekey的update方法,将标签的ID、分页信息、SQL语句、参数等信息作为参数传入:
1 |
|
- 通过源码,看一下CacheKey的update方法,update方法中记录了调用update传入参数的次数、每个传入参数的hashcode之和checksum、以及计算CacheKey的成员变量hashcode的值。
1 | public class CacheKey implements Cloneable, Serializable { |
- CacheKey中的成员变量的作用是什么呢,接下来看一下它的equals方法,CacheKey中重写了equals方法,CacheKey中的成员变量其实就是为了判断两个CacheKey的实例是否相同:
如果满足以下条件,两个CacheKey将判为不相同:
要比较的对象不是CacheKey的实例
CacheKey对象中的hashcode不相同、count不相同、checksum不相同(它们之间是或的关系)
CacheKey对象的updateList成员变量不相同
总结:
如果Statement Id + Offset + Limmit + Sql + Params 都相同将被认为是相同的SQL,第一次将CacheKey作为HashMap中的key,数据库返回的数据作为value放入到集合中,第二次查询时由于被认为是相同的SQL,HashMap中已经存在该SQL的CacheKey对象,可直接从localCache中获取数据来实现mybatis的一级缓存。
1 |
|
总结:
(1)mybatis的一级缓存是SqlSession级别的,不同的SqlSession不共享缓存;
(2)mybatis一级缓存是通过HashMap实现的,在PerpetualCache中定义,没有容量控制;
(3)分布式环境下使用一级缓存,数据库写操作会引起脏数据问题;