mybatis的一级缓存

1、mybatis缓存使用场景

 

 

2、mybatis一级缓存命中场景

 

 

 当mybatis执行相关右边的操作时,均会执行clearCache()方法,清空对应缓存。

一级缓存的作用域默认是sqlsession,也就是同一个会话。但是也可以设置为statement级别缓存,此时级别变小了。此时只有同一个statement的子查询才会命中缓存。

只有满足左边条件才能命中缓存。

一级缓存的key值,总共有6个值,0是statementid,1、2是分页条件,3是sql,4是参数,5是环境变量和命中场景中的参数一一对应。

 

 

 

3、mybatis中缓存执行过程

 

 

 

 

 

 

 

复制代码
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 (closed) {
      throw new ExecutorException("Executor was closed.");
    }
    if (queryStack == 0 && ms.isFlushCacheRequired()) {
      clearLocalCache();//对于嵌套查询只有第一次查询才会清空缓存,子查询不会清空缓存。
    }
    List<E> list;
    try {
      queryStack++;//嵌套查询使用   
      list = resultHandler == null ? (List<E>) localCache.getObject(key) : null;//resulthandle不为空表示自定义了结果集处理函数,此时就不需要走缓存了,因为你要自定义处理缓存
      if (list != null) {//存在缓存,直接使用
        handleLocallyCachedOutputParameters(ms, key, parameter, boundSql);
      } else {//不存在缓存,查询数据库
        list = queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql);
      }
    } finally {
      queryStack--;
    }
    if (queryStack == 0) {
      for (DeferredLoad deferredLoad : deferredLoads) {
        deferredLoad.load();
      }
      // issue #601
      deferredLoads.clear();
      if (configuration.getLocalCacheScope() == LocalCacheScope.STATEMENT) {
        // issue #482
        clearLocalCache();//判断缓存作用域,如果是statment则直接删除缓存
      }
    }
    return list;
  }
复制代码

3.spring继承mybatis时,一级缓存失效?

因为spring默认每一个查询都是一个事务,一个事务对应一个sqlsession会话,此时不在一个会话,当然不能命中。

只需要在查询中加上事务,就可以解决。

spring获取会话的数据结构。

 

 

 

 

 

 

复制代码
private <E> List<E> queryFromDatabase(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
    List<E> list;
    localCache.putObject(key, EXECUTION_PLACEHOLDER);//占位符,嵌套查询使用,防止死循环
    try {
      list = doQuery(ms, parameter, rowBounds, resultHandler, boundSql);
    } finally {
      localCache.removeObject(key);//为了更新结果
    }
    localCache.putObject(key, list);//缓存结果
    if (ms.getStatementType() == StatementType.CALLABLE) {
      localOutputParameterCache.putObject(key, parameter);
    }
    return list;//返回结果
  }
复制代码

 

posted @   小南的歌  阅读(734)  评论(0编辑  收藏  举报
编辑推荐:
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
阅读排行:
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?
点击右上角即可分享
微信分享提示