您的位置:首页 > 其它

Mybatis一级缓存实现原理

2016-11-23 00:00 260 查看
Mybatis将缓存设计成两级结构,一级缓存是sqlSession级别的,同一个会话中查询多次相同sql不需要都去查数据库,二级缓存是Mapper级别的,多个会话去执行同一个Mapper的sql数据缓存在同一个地方,本文讲解一级缓存(本地缓存)内部机制,下图是整个缓存总体结构图:



一、一级缓存存在的意义

每当开启一次和数据库的会话,Mybatis会创建一个sqlSession表示会话,在一次会话中可能会重复查询多次数据库,每一次查询都会发起一次网络请求,这个代价很大,所以可以把第一次查询的结果缓存起来,同一个会话如果是完全一样的查询直接把缓存结果返回,这也是mybatis默认开启的。

二、一级缓存的生命周期

sqlSession查询数据库时把工作交给Executor,每次创建Executor时会创建本地缓存PerpetualCache对象,会话结束会销毁本地缓存对象,会话中执行任何增删改操作都会把缓存清空。

上面PerpetualCache里面实际上就是一个HashMap, 这里的HashMap没有做大小限制,原因是本地缓存生命周期很短,同一个会话中不会连续调用太多次查询。

三、缓存key的定义

如果缓存中有查询保留的记录则直接返回,怎样确定是完全一样的查询,这是通过相关条件构造CacheKey唯一确定一次查询,通过createCacheKey方法看到有四种参数确定唯一查询:
1. statementId
2. RowBounds的offset和limit
3. sql语句
4. 查询参数

public CacheKey createCacheKey(MappedStatement ms, Object parameterObject, RowBounds rowBounds, BoundSql boundSql) {
if (closed)
throw new ExecutorException("Executor was closed.");
CacheKey cacheKey = new CacheKey();
//statementId
cacheKey.update(ms.getId());
//分页数据
cacheKey.update(rowBounds.getOffset());
cacheKey.update(rowBounds.getLimit());
//sql
cacheKey.update(boundSql.getSql());
List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
TypeHandlerRegistry typeHandlerRegistry = ms.getConfiguration().getTypeHandlerRegistry();
//sql参数
for (int i = 0; i < parameterMappings.size(); i++) {
ParameterMapping parameterMapping = parameterMappings.get(i);
if (parameterMapping.getMode() != ParameterMode.OUT) {
Object value;
String propertyName = parameterMapping.getProperty();
if (boundSql.hasAdditionalParameter(propertyName)) {
value = boundSql.getAdditionalParameter(propertyName);
} else if (parameterObject == null) {
value = null;
} else if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {
value = parameterObject;
} else {
MetaObject metaObject = configuration.newMetaObject(parameterObject);
value = metaObject.getValue(propertyName);
}
cacheKey.update(value);
}
}
return cacheKey;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息