2.一级缓存本质是什么?一级缓存什么时候被创建?一级缓存的工作流程?

MyBatis一级缓存

问题:
1.一级缓存到底是什么?
2.一级缓存什么时候被创建?
3.一级缓存的工作流程是怎样的?

源码分析流程

一级缓存到底是什么?解答

由于一级缓存与SqlSession有关下面分析从SqlSession接口方法入手
1.找到SqlSession中与缓存相关的方法-clearCache();
2.进入SqlSessoin实现类DefaultSqlSession,发现实现clearCache()的代码是

private final Executor executor;
public void clearCache() {
    
    
 this.executor.clearLocalCache();
 }

3.进入 Executor的实现类BaseExecutor实现clearLocalCache();的代码是

protected PerpetualCache localCache;
protected PerpetualCache localOutputParameterCache;
public void clearLocalCache() {
    
    
        if (!this.closed) {
    
    
            this.localCache.clear();
            this.localOutputParameterCache.clear();
        }

    }

3.进入PerpetualCache类clear();发现执行的是Map的clear方法;

 private Map<Object, Object> cache = new HashMap();
public void clear() {
    
    
        this.cache.clear();
    }

4.由此发现问题一中一级缓存是什么的答案是:一级缓存就是一个Map集合,一个SqlSession中有一个。

一级缓存什么时候被创建?一级缓存的工作流程是怎样的?解答

一级缓存应该是在首次查询时候创建
1.进入Sqsession的实现类DefaultSqlSession中selectList(String statement, Object parameter, RowBounds rowBounds);底层调用了SQL执行器Executor的query方法。

public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
    
    
        List var5;
        try {
    
    
            MappedStatement ms = this.configuration.getMappedStatement(statement);
            var5 = this.executor.query(ms, this.wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER);
        } catch (Exception var9) {
    
    
            throw ExceptionFactory.wrapException("Error querying database.  Cause: " + var9, var9);
        } finally {
    
    
            ErrorContext.instance().reset();
        }
  1. Executor的实现类BaseExecutor实现query方法,发现CacheKey与createCacheKey方法,
    又源码得知CacheKey由MappedStatement(mapper映射封装实体类) +parameter(入参)+RowBounds (分页参数)构成;
Override 
public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {
    
    
 BoundSql boundSql = ms.getBoundSql(parameter);
  //创建缓存 
  CacheKey key = createCacheKey(ms, parameter, rowBounds, boundSql);
   return this.query(ms, parameter, rowBounds, resultHandler, key, boundSql);
}
 public CacheKey createCacheKey(MappedStatement ms, Object parameterObject, RowBounds rowBounds, BoundSql boundSql) {
    
    
        if (this.closed) {
    
    
            throw new ExecutorException("Executor was closed.");
        } else {
    
    
        
            CacheKey cacheKey = new CacheKey();
            //MappedStatement 的 id 
        // id就是Sql语句的所在位置包名+类名+ SQL名称
            cacheKey.update(ms.getId());
            // offset 就是 从索引为0的第一条数据开始取 , limit 0,Integer.MAXVALUE
            cacheKey.update(rowBounds.getOffset());
            // limit 就是 Integer.MAXVALUE,从索引为0的第一条数据开始取Integer.MAXVALUE条数据
            cacheKey.update(rowBounds.getLimit());
            //具体的SQL语句
            cacheKey.update(boundSql.getSql());
            List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
            TypeHandlerRegistry typeHandlerRegistry = ms.getConfiguration().getTypeHandlerRegistry();
            Iterator var8 = parameterMappings.iterator();

            while(var8.hasNext()) {
    
    
                ParameterMapping parameterMapping = (ParameterMapping)var8.next();
                if (parameterMapping.getMode() != ParameterMode.OUT) {
    
    
                    String propertyName = parameterMapping.getProperty();
                    Object value;
                    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 = this.configuration.newMetaObject(parameterObject);
                        value = metaObject.getValue(propertyName);
                    }
					//后面是update 了 sql中带的参数
                    cacheKey.update(value);
                }
            }

            if (this.configuration.getEnvironment() != null) {
    
    
                cacheKey.update(this.configuration.getEnvironment().getId());
            }

            return cacheKey;
        }
    }

3.然后进入BaseExecutor的this.query(ms, parameter, rowBounds, resultHandler, key, boundSql);查询部分

//一级缓存
protected PerpetualCache localCache;
public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
    
    
        ErrorContext.instance().resource(ms.getResource()).activity("executing a query").object(ms.getId());
        if (this.closed) {
    
    
            throw new ExecutorException("Executor was closed.");
        } else {
    
    
            if (this.queryStack == 0 && ms.isFlushCacheRequired()) {
    
    
                this.clearLocalCache();
            }

            List list;
            try {
    
    
                ++this.queryStack;
                // 缓存中获取
                list = resultHandler == null ? (List)this.localCache.getObject(key) : null;
                if (list != null) {
    
    
                //如果存在封装结果直接返回
                    this.handleLocallyCachedOutputParameters(ms, key, parameter, boundSql);
                } else {
    
    
                //如果没有再去查询
                    list = this.queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql);
                }
            } finally {
    
    
                --this.queryStack;
            }

            if (this.queryStack == 0) {
    
    
                Iterator var8 = this.deferredLoads.iterator();

                while(var8.hasNext()) {
    
    
                    BaseExecutor.DeferredLoad deferredLoad = (BaseExecutor.DeferredLoad)var8.next();
                    deferredLoad.load();
                }

                this.deferredLoads.clear();
                if (this.configuration.getLocalCacheScope() == LocalCacheScope.STATEMENT) {
    
    
                    this.clearLocalCache();
                }
            }

            return list;
        }
    }
private <E> List<E> queryFromDatabase(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
    
    
        this.localCache.putObject(key, ExecutionPlaceholder.EXECUTION_PLACEHOLDER);

        List list;
        try {
    
    
        //查询获取最新的值
            list = this.doQuery(ms, parameter, rowBounds, resultHandler, boundSql);
        } finally {
    
    
        //情况原有缓存
            this.localCache.removeObject(key);
        }
		// 更新最新缓存结果值
        this.localCache.putObject(key, list);
        if (ms.getStatementType() == StatementType.CALLABLE) {
    
    
            this.localOutputParameterCache.putObject(key, parameter);
        }

        return list;
    }

4.解决了问题一级缓存是什么时候创建的:一级缓存实在第一次查询时创建的。
解决了问题一级缓存的工作流程是什么:第一次查询时后创建,第二次查询的时候会先去缓存中查询是否存在不存在则再次查询,并将查询结果放入缓存,如果存在则直接返回。

猜你喜欢

转载自blog.csdn.net/yangxiaofei_java/article/details/111060260