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

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

躺平程序猿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值