mybatis緩存機制詳解(一)——Cache

緩存概述
java

在mybatis中,緩存的功能由根接口Cache(org.apache.ibatis.cache.Cache)定義。整個體系採用裝飾器設計模式,數據存儲和緩存的基本功能由PerpetualCache(org.apache.ibatis.cache.impl.PerpetualCache)永久緩存實現,而後經過一系列的裝飾器來對PerpetualCache永久緩存進行緩存策略等方便的控制。以下圖:算法

用於裝飾PerpetualCache的標準裝飾器共有8個(所有在org.apache.ibatis.cache.decorators包中):apache

1.FifoCache:先進先出算法,緩存回收策略設計模式

2.LoggingCache:輸出緩存命中的日誌信息緩存

3.LruCache:最近最少使用算法,緩存回收策略mybatis

4.ScheduledCache:調度緩存,負責定時清空緩存多線程

5.SerializedCache:緩存序列化和反序列化存儲併發

6.SoftCache:基於軟引用實現的緩存管理策略app

7.SynchronizedCache:同步的緩存裝飾器,用於防止多線程併發訪問框架

8.WeakCache:基於弱引用實現的緩存管理策略

另外,還有一個特殊的裝飾器TransactionalCache:事務性的緩存


正如大多數持久層框架同樣,mybatis緩存一樣分爲一級緩存和二級緩存

一級緩存,又叫本地緩存,是PerpetualCache類型的永久緩存,保存在執行器中(BaseExecutor),而執行器又在SqlSession(DefaultSqlSession)中,因此一級緩存的生命週期與SqlSession是相同的

二級緩存,又叫自定義緩存,實現了Cache接口的類均可以做爲二級緩存,因此可配置如encache等的第三方緩存。二級緩存以namespace名稱空間爲其惟一標識,被保存在Configuration核心配置對象中。以下:

public class Configuration {
    // ...
    protected final Map<String, Cache> caches = new StrictMap<Cache>("Caches collection");
    // ...
}

每次構建SqlSessionFactory對象時都會建立新的Configuration對象,所以,二級緩存的生命週期與SqlSessionFactory是相同的。在建立每一個MapperedStatement對象時,都會根據其所屬的namespace名稱空間,給其分配Cache緩存對象。


二級緩存對象的默認類型爲PerpetualCache,若是配置的緩存是默認類型,則mybatis會根據配置自動追加一系列裝飾器。

Cache對象之間的引用順序爲:

SynchronizedCache-->LoggingCache-->SerializedCache-->ScheduledCache-->LruCache-->PerpetualCache


全部的緩存對象的操做與維護都是由Executor器執行來完成的,一級緩存由BaseExecutor(包含SimpleExecutor、ReuseExecutor、BatchExecutor三個子類)負責維護,二級緩存由CachingExecutor負責維護。所以須要注意的是:配置了二級緩存不表明mybatis就會使用二級緩存,還須要確保在建立SqlSession的過程當中,mybatis建立是CachingExecutor類型的執行器。

Executor中對Cache的具體操做邏輯,請點擊mybatis核心組件詳解——Executor


源碼解讀:

Cache接口:

package org.apache.ibatis.cache;

import java.util.concurrent.locks.ReadWriteLock;


/**
 * 緩存接口
 * 給緩存供應商的SPI(Service Provider Interface)
 * 一個Cache的實例將爲名稱空間被建立
 * Cache接口的實現類必須有一個具備String類型參數的構造方法,用於接收Cache對象的id,做爲其惟一標識
 * 
 * mybatis將以namespace做爲id調用這個構造函數建立對象
 * 
 * @author Administrator
 *
 */
public interface Cache {

	/**
	 * 獲取緩存對象的惟一標識
	 * @return
	 */
	String getId();

	/**
	 * 保存key/value到緩存對象中
	 * key能夠是任何對象,但通常是CacheKey對象
	 * value是查詢結果,爲List類型
	 * @param key
	 * @param value
	 */
	void putObject(Object key, Object value);

	/**
	 * 從緩存對象中獲取key對應的value
	 * @param key
	 * @return
	 */
	Object getObject(Object key);

	/**
	 * 可選的方法,沒有被核心框架調用,移除key對應的value
	 * @param key
	 * @return
	 */
	Object removeObject(Object key);

	/**
	 * 清空緩存
	 */
	void clear();

	/**
	 * 獲取緩存對象中存儲的鍵/值對的數量
	 * 可選的方法,沒有被框架核心調用
	 */
	int getSize();

	/**
	 * 獲取讀寫鎖
	 * 可選的方法,從3.2.6起這個方法再也不被框架核心調用
	 * 任何須要的鎖,都必須由緩存供應商提供
	 * 
	 * @return A ReadWriteLock
	 */
	ReadWriteLock getReadWriteLock();

}

PerpetualCache永久緩存:

package org.apache.ibatis.cache.impl;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.ReadWriteLock;

import org.apache.ibatis.cache.Cache;
import org.apache.ibatis.cache.CacheException;

/**
 * 永久緩存 Cache接口實現類
 * Cache接口只有這惟一一個基礎實現,其餘實現類全都是裝飾模式持有另外一個緩存對象
 * 
 * @author Administrator
 *
 */
public class PerpetualCache implements Cache {
	// 緩存對象的惟一標識
	private String id;
	// 對象內部維護的HashMap
	private Map<Object, Object> cache = new HashMap<Object, Object>();

	public PerpetualCache(String id) {
		this.id = id;
	}

	public String getId() {
		return id;
	}

	public int getSize() {
		return cache.size();
	}

	public void putObject(Object key, Object value) {
		cache.put(key, value);
	}

	public Object getObject(Object key) {
		return cache.get(key);
	}

	public Object removeObject(Object key) {
		return cache.remove(key);
	}

	public void clear() {
		cache.clear();
	}

	public ReadWriteLock getReadWriteLock() {
		return null;
	}

	public boolean equals(Object o) {
		if (getId() == null)
			throw new CacheException("Cache instances require an ID.");
		if (this == o)
			return true;
		if (!(o instanceof Cache))
			return false;

		Cache otherCache = (Cache) o;
		return getId().equals(otherCache.getId());
	}

	public int hashCode() {
		if (getId() == null)
			throw new CacheException("Cache instances require an ID.");
		return getId().hashCode();
	}

}

在mybatis中,PerpetualCache是惟一的Cache接口的基礎實現。它內部維護一個HashMap,全部的緩存操做,其實都是對這個HashMap的操做。

其餘Cache接口的實現類所有爲裝飾器,源碼詳解請點擊mybatis緩存機制詳解(二)——緩存裝飾器

相關文章
相關標籤/搜索