【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的每次查詢都會清空緩存后在執行。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM