mybatis缓存

执行sql,需用SqlSession,就类似jdbc
jdbc:
1.获取驱动 Drever.get(XXXX);
2.获取链接connection;
3.statement,prestatement进行sql语句与参数拼装
4.到数据库执行
5.ResultSet返回,
6.实体映射封装返回


mybatis其实就是把statement,prestatement给封装了下
mybatis:
1.执行器Executor:SQL执行过程的总体控制
2、StatementHandler:语句处理器负责和JDBC层具体交互,包括prepare语句,执行语句
3、ParameterHandler:参数处理器负责PreparedStatement入参的具体设置
4、ResultSetHandler:结果处理器负责将JDBC查询结果映射到java对象
tips:二级缓存放在了Map里面
详情看下面的源码

 

 

 

 

 

 

以下是mybatis源码:

 

  @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 query(ms, parameter, rowBounds, resultHandler, key, boundSql);
  }

 

@Override
  public CacheKey createCacheKey(MappedStatement ms, Object parameterObject, RowBounds rowBounds, BoundSql boundSql) {
   //判断执行器是否关闭   
 if (closed) {
      throw new ExecutorException("Executor was closed.");
    }
    CacheKey cacheKey = new CacheKey();
//1、将Statement中的id添加到CacheKey对象中的updateList属性  ,这个ID是某个方法所在的dAO(持久层方法全路径)
    cacheKey.update(ms.getId());
//2、将offset(分页偏移量)添加到CacheKey对象中的updateList属性(如果没有分页则默认0)
    cacheKey.update(rowBounds.getOffset());
//3、将limit(每页显示的条数)添加到CacheKey对象中的updateList属性(如果没有分页则默认Integer.MAX_VALUE)
    cacheKey.update(rowBounds.getLimit());
//4、将sql语句(包括占位符?)添加到CacheKey对象中的updateList属性
    cacheKey.update(boundSql.getSql());
    List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
    TypeHandlerRegistry typeHandlerRegistry = ms.getConfiguration().getTypeHandlerRegistry();
    // mimic DefaultParameterHandler logic
//5、循环用户传入的参数,并将每个参数添加到CacheKey对象中的updateList属性
    for (ParameterMapping parameterMapping : parameterMappings) {
      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);
      }
    }
    if (configuration.getEnvironment() != null) {
      // issue #176  
//6、如果有配置Environment,则将Environment中的id添加到CacheKey对象中的updateList属性
      cacheKey.update(configuration.getEnvironment().getId());
    }
    return cacheKey;
  }

 

  @SuppressWarnings("unchecked")
  @Override
  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.");
    }
//查询次数为0,或者需要清除缓存属性为true:清楚本地缓存(一级缓存)
    if (queryStack == 0 && ms.isFlushCacheRequired()) {
      clearLocalCache();
    }
    List<E> list;
    try {
      queryStack++;
//结果处理器为空,从缓存获取
      list = resultHandler == null ? (List<E>) localCache.getObject(key) : null;
      if (list != null) {
 //缓存list不为空,从缓存获取
        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;
  }

 

 

 

//缓存获取  对应://缓存list不为空,从缓存获取
  private void handleLocallyCachedOutputParameters(MappedStatement ms, CacheKey key, Object parameter, BoundSql boundSql) {
    if (ms.getStatementType() == StatementType.CALLABLE) {
      final Object cachedParameter = localOutputParameterCache.getObject(key);
      if (cachedParameter != null && parameter != null) {
        final MetaObject metaCachedParameter = configuration.newMetaObject(cachedParameter);
        final MetaObject metaParameter = configuration.newMetaObject(parameter);
        for (ParameterMapping parameterMapping : boundSql.getParameterMappings()) {
          if (parameterMapping.getMode() != ParameterMode.IN) {
            final String parameterName = parameterMapping.getProperty();
            final Object cachedValue = metaCachedParameter.getValue(parameterName);
            metaParameter.setValue(parameterName, cachedValue);
          }
        }
      }
    }
  }

 

 

//从数据库获取
  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) {
//放入Map
      localOutputParameterCache.putObject(key, parameter);
    }
    return list;
  }

 

 
解释数据库里面那个localOutputParameterCache参数,这个参数最终操作是放入Map
 protected PerpetualCache localOutputParameterCache;
 @Override
  public void putObject(Object key, Object value) {
    cache.put(key, value);
  }
  private final Map<Object, Object> cache = new HashMap<>();

 

posted @ 2022-01-18 14:02  余生请多指教ANT  阅读(43)  评论(0编辑  收藏  举报