Mybatis-一級緩存

Mybatis有兩級緩存,一級緩存是在同一個SqlSession中有效,兩次徹底相同的查詢,第二次就是從本地緩存中獲得上一次的查詢結果java

Mybatis是默認開啓一級緩存的,沒法關閉。好比在一個會話中連續兩次執行同一個方法, 獲得的是同一個對象sql

一級緩存在一下六種狀況會失效:
           1.不一樣的會話
           2.同一個會話,兩次相同查詢中間有增刪改操做,由於都會調用clearLocalCache()方法清除緩存
           3.同一個會話,查詢(條件)參數不一樣
           4.同一個會話,調用清楚會話內容操做 SqlSession.flushCache()
           5.同一個會話,SQL相同與條件(參數)相同,可是方法名不一樣
           6.同一個會話,分頁信息(偏移量和須要返回的記錄數)不一樣數據庫

舉例:緩存

public void testCache1() {
		
		SqlSession session = getSqlSession();
		CustMapper mapper = session.getMapper(CustMapper.class);
		//SQL:select cust_id,cust_name from cust where cust_id=#{custId};
		Cust cust1 = mapper.getCustById(1);
		//SQL:select cust_id,cust_name from cust where cust_id=#{custId};
		//雖然getCustById和getCustByIdNew使用的相同條件和相同SQL,但方法不一樣不能使用緩存
		Cust cust2 = mapper.getCustByIdNew(1);

		//若是在這裏執行一個增刪改操做,那麼本地緩存中的 數據將會被清空,下面的getCustByIdNew(1)會再次從數據庫中查詢數據
		//mapper.addCust(new Cust("TonTan"))
		
		//由於和Cust cust2 = mapper.getCustByIdNew(1);方法名(全類名+方法名)、條件、SQL、默認分頁信息都同樣因此可使用緩存
		Cust cust3 = mapper.getCustByIdNew(1);
		
	}

 

附上一些源碼分析:session

一級緩存是使用了名爲PerpetualCache的類,變量名爲localCache,其內部就是一個Map<Object,Object>。app

public class PerpetualCache implements Cache {

  private final String id;

  private Map<Object, Object> cache = new HashMap<Object, Object>();

}

Mybatis每次執行查詢的時候會執行localCache.get(key),這個Key是CacheKey類,他的hashCode值是由以下幾個因素決定,只要這幾個因素徹底一致就能夠從localCache中找到以前的查詢結果。生成key的方法以下:源碼分析

public CacheKey createCacheKey(MappedStatement ms, Object parameterObject, RowBounds rowBounds, BoundSql boundSql) {
    if (closed) {
      throw new ExecutorException("Executor was closed.");
    }
    CacheKey cacheKey = new CacheKey();
    cacheKey.update(ms.getId());
    cacheKey.update(rowBounds.getOffset());
    cacheKey.update(rowBounds.getLimit());
    cacheKey.update(boundSql.getSql());
    //其餘部分沒有複製出來
}

ms.getId是方法的全類名+方法名
rowBounds.getOffset()分頁查詢時的偏移量
rowBounds.getLimit()分頁查詢時的查詢記錄數
boundSql.getSql()sql自己code

何時將查詢結果放入緩存的喃?對象

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

localCache.putObject(key, list);就是它了。。。。。。。rem

那爲何調用了增刪改緩存就失效了喃,由於他們都底層都是調用update方法,而它調用了clearLocalCache(),因此。。你懂的。

 

最後提一個全局配置參數:localCacheScope,它能夠設置爲SESSION或者STATEMENT,默認爲SESSION,可是這樣的話,可能取到髒數據,假如設置爲STATEMENT的話就能夠避免這種狀況,至關於禁止了一級緩存。

相關文章
相關標籤/搜索