• 【mybatis】多次查询缓存的问题


    转自:http://cheng-xinwei.iteye.com/blog/2021700?utm_source=tuicool&utm_medium=referral

         最近在使用mybatis的过程中,发现一个问题。如果在同一个事物中,多次同一个查询sql在mybatis的执行过程中,只会查询一次数据库,后几次所返回的对象是mybatis在在内部做了缓存。 

    Property property = this.findByPropertyId("123");  
    property.setPropertyId(null);;  
    property = this.findByPropertyId("123");  
    System.out.println(property.getPropertyId());  

    以上的代码,打印的结果为 null , 但是我们所期望的可能是 123 , 我不知道这是mybatis的一个bug还是故意这样去设计的.mybatis在执行查询语句的时候,会在本地做一份缓存信息.在BaseExecutor类中: 

    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;

          可以看到在queryFromDatabase方法中,查询数据库返回结果之后,mybatis编制了一个cachekey的对象,作为key,返回结果作为value,放入了缓存当中(这个地方没有使用拷贝的函数,所以只要外部修改了值,内部缓存中的值信息也会被修改) 

        之后再下次查询的时候,会依据一个判断,是否需要执行缓存信息,同样是在BaseExecutor类中。

    @SuppressWarnings("unchecked")  
    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();  
        }  
        deferredLoads.clear(); // issue #601  
        if (configuration.getLocalCacheScope() == LocalCacheScope.STATEMENT) {  
          clearLocalCache(); // issue #482  
        }  
      }  
      return list;  
    } 

          看到mybatis判断了 ms.isFlushCacheRequired() 的返回数据,如果为 true 会执行 clearLocalCache 方法,清空缓存信息。如果缓存中获取不到的话,才会继续去查询数据库。 

    可以从   list = resultHandler == null ? (List<E>) localCache.getObject(key) : null; 代码中看出。 

       所以当第一次查询放入缓存之后,在外部修改了任何一个值之后,mybatis内部缓存的值也会被修改,而且下次查询不会查询数据库,直接返回缓存中被修改过的值 


        ms.isFlushCacheRequired() 这段代码的判断是基于了一个MappedStatement 类中的flushCacheRequired 的属性做判断的。flushCacheRequired  变量可以通过注解的方式和xml的方式来配置 
        
        1.注解:注解的方式是通过 @Options 注解中 flushCache 的配置 
        2.配置文件:xml中每一个select 都可以设置 flushCache 的属性 

        flushCache 设置成true之后,本sql的每次查询都会清空缓存后在执行。

  • 相关阅读:
    【HDOJ6701】Make Rounddog Happy(启发式合并)
    【HDOJ6731】Angle Beats(极角排序)
    【BZOJ1132】Tro(叉积)
    【CF1236D】Alice and the Doll(set)
    Storm
    Spark
    Python基础(2)
    数据库漫谈
    Python基础(1)
    C/C++链接过程相关
  • 原文地址:https://www.cnblogs.com/tv151579/p/5742371.html
Copyright © 2020-2023  润新知