Mybatis源码解析(二)

Mybatis源码解析(二)

一、我们从下面这段代码开始

  @Test
    public void testCahce1() {
    
    
        UserMapper mapper = session.getMapper(UserMapper.class);
        User user = mapper.selectByid(1);
        session.close();
        User user2 = sqlSessionFactory.openSession(true)
                .getMapper(UserMapper.class)
                .selectByid(1);
        System.out.println(user == user2);
        System.out.println(user);
        System.out.println(user2);
    }

流程图
在这里插入图片描述
二、源码分析(此处只分析主要代码,详细看流程图)

CachingExecutor#query

 public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql)
      throws SQLException {
    
    
    Cache cache = ms.getCache();
    if (cache != null) {
    
    
    //已经开启了二级缓存,走if里面逻辑
      flushCacheIfRequired(ms);
      if (ms.isUseCache() && resultHandler == null) {
    
    
        ensureNoOutParams(ms, boundSql);
        @SuppressWarnings("unchecked")
        //逐级调用,最后从PerpetualCache获取
        List<E> list = (List<E>) tcm.getObject(cache, key);
        if (list == null) {
    
    
        	//二级缓存中没有,调用一级缓存(如果没有从数据库中获取)
          list = delegate.<E> query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
          //存在TransactionalCache中entriesToAddOnCommit.put(key, object);
          tcm.putObject(cache, key, list); // issue #578 and #116
        }
        return list;
      }
    }
    //二级缓存没有开启,走一级缓存
    return delegate.<E> query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
  }

BaseExecutor#query

 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;
      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();
      }
    }
    return list;
  }

BaseExecutor#queryFromDatabase

  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;
  }

下面我们来看一下在什么地方存储二级缓存TransactionalCache#commit

  public void commit() {
    
    
    if (clearOnCommit) {
    
    
      delegate.clear();
    }
    flushPendingEntries();
    reset();
  }
private void flushPendingEntries() {
    
    
    for (Map.Entry<Object, Object> entry : entriesToAddOnCommit.entrySet()) {
    
    
     //逐级调用,保存到PerpetualCache中
      delegate.putObject(entry.getKey(), entry.getValue());
    }
    for (Object entry : entriesMissedInCache) {
    
    
      if (!entriesToAddOnCommit.containsKey(entry)) {
    
    
        delegate.putObject(entry, null);
      }
    }
  }

二级缓存清除
CachingExecutor#update执行增删改清理缓存

  @Override
  public int update(MappedStatement ms, Object parameterObject) throws SQLException {
    
    
    flushCacheIfRequired(ms);
    return delegate.update(ms, parameterObject);
  }
  private void flushCacheIfRequired(MappedStatement ms) {
    
    
    Cache cache = ms.getCache();
    if (cache != null && ms.isFlushCacheRequired()) {
    
          
      tcm.clear(cache);
    }
  }
 public void clear(Cache cache) {
    
    
    getTransactionalCache(cache).clear();
  }

同一会话一级缓存清除
BaseExecutor#update

 @Override
  public int update(MappedStatement ms, Object parameter) throws SQLException {
    
    
    ErrorContext.instance().resource(ms.getResource()).activity("executing an update").object(ms.getId());
    if (closed) {
    
    
      throw new ExecutorException("Executor was closed.");
    }
    clearLocalCache();
    return doUpdate(ms, parameter);
  }
  @Override
  public void clearLocalCache() {
    
    
    if (!closed) {
    
    
      localCache.clear();
      localOutputParameterCache.clear();
    }
  }

三、结束,对于这一块代码,只要你认真跑一遍,你会发现并不难。重点:一级缓存是在创建SqlSession过程中创建的,生命周期为一次请求。二级缓存是在创建SqlSessionFactory过程中创建的,生命周期是应用结束。

猜你喜欢

转载自blog.csdn.net/mlplds/article/details/103557203