1、包概述(org.apache.ibatis.cache)html
本包包含了Mybatis框架的緩存接口的定義和實現。
本包只引用了Mybatis的io包的Resources,不依賴於任何第三方庫。
Mybatis的其它包大量引用了本包中的類和接口,即嚴重依賴於本包。
2、類和接口概述
緩存框架按照 Key-Value方式存儲,Key的生成採起規則爲:[hashcode:checksum:mappedStementId:offset:limit:executeSql:queryParams]。
Cache接口定義了緩存接口。apache
CacheKey定義了緩存的Key。
PerpetualCache直接實現了Cache接口。
FifoCache,LoggingCache,LruCache,ScheduledCache,SerializedCache,SoftCache,SynchronizedCache,
TransactionalCache,WeakCache 採用裝飾模式實現Cache接口。
採用裝飾模式,一個個包裝起來,造成一個鏈,典型的就是SynchronizedCache->LoggingCache->SerializedCache->LruCache->PerpetualCache,經過鏈起來達到功能增長。
CacheException定義了緩存異常。
3、緩存接口的定義
緩存
public interface Cache {
// 緩存實現類的id
String getId();數據結構
// 緩存的對象的個數
int getSize();多線程
// 放入一個緩存對象
void putObject(Object key, Object value);app
// 得到一個緩存對象
Object getObject(Object key);框架
// 刪除一個緩存對象
Object removeObject(Object key);post
// 清空緩存對象
void clear();性能
// 獲取讀寫鎖
ReadWriteLock getReadWriteLock();spa
}
4、緩存Key的設計
通常緩存框架的數據結構基本上都是 Key-Value方式存儲。 MyBatis對於其Key的生成採起規則爲:
[hashcode:checksum:mappedStementId :offset:limit:executeSql:queryParams]。
(待深刻研究和完善)
5、緩存實現類和包裝類
實現類:PerpetualCache, 永久緩存,一旦存入就一直保持,內部就是一個HashMap,全部方法基本就是直接調用HashMap的方法。
內部維護一個Map數據結構,private Map<Object, Object> cache = new HashMap<Object, Object>();
包裝類:
FifoCache:先進先出緩存,內部就是一個鏈表,將鏈表開頭元素(最老)移除。
LoggingCache:日誌緩存,添加功能:取緩存時打印命中率。
LruCache:最近最少使用緩存,核心就是覆蓋 LinkedHashMap.removeEldestEntry方法,返回true或false告訴 LinkedHashMap要不要刪除此最老鍵值。
LinkedHashMap內部其實就是每次訪問或者插入一個元素都會把元素放到鏈表末尾,這樣不常常訪問的鍵值確定就在鏈表開頭啦。
ScheduledCache:定時調度緩存, 目的是每一小時清空一下緩存。
SerializedCache:序列化緩存,用途是先將對象序列化成2進制,再緩存向緩存中 put或get數據時的序列化及反序列化處理。、
SoftCache:軟引用緩存,核心是SoftReference。
SynchronizedCache:同步緩存,防止多線程問題。
核心: 加讀寫鎖, ReadWriteLock.readLock().lock()/unlock() ,ReadWriteLock.writeLock().lock()/unlock()
對於 Lock機制來講,其分爲 Read 和 Write 鎖,其 Read 鎖容許多個線程同時持有,而 Write 鎖,一次能被一個線程持有,若是當 Write 鎖沒有釋放,其它須要 Write的線程只能等待其釋放才能去持有。
TransactionalCache:
事務緩存,一次性存入多個緩存,移除多個緩存 。
咱們能夠看到在TransactionalCache類裏也維護着兩個HashMap:
entriesToAddOnCommit和entriesToRemoveOnCommit。
當在TransactionalCacheManager中調用putObject和removeObject方法的時候並非立刻就把對象存放到緩存或者從緩存中刪除 ,而是先把這個對象放到這兩個HashMap之中的一個裏,而後當執行commit方法時再真正地把對象存放到緩存或者從緩存中刪除。
如今咱們應該能夠明白爲TransactionalCacheManager和TransactionalCache這兩個類要加上事務的前綴了,由於commit方法是一個原子操做,一次會操做多個對象,要麼一塊兒成功,要麼就一塊兒失敗。
WeakCache:弱引用緩存,核心是WeakReference。
6、緩存實現的問題和解決方案(待深刻研究和完善)
問題:
1.做爲緩存中對象的key是它的CacheKey對象。
不得不說這是一個失敗的設計,key值的類型是String類型就已經足夠了,徹底沒有必要用對象類型來作key值的類型。
由於內存空間是有限的,要在有限的空間中儘量地存放更多的內容,就須要key值在保證惟一性的狀況下空間佔的越小越好。
2.myBatis的讀寫鎖有寫飢渴問題等,這些問題都會給性能形成影響。
因此仍是不建議在生產環境中使用iBatis或者myBatis自帶的二級緩存,只使用他們的ORM功能,而二級緩存仍是交給Memcached等其它緩存框架來實現吧。
memcache:http://baike.baidu.com/view/1193094.htm
oscache:http://baike.baidu.com/view/1835163.htm
ehcache:http://baike.baidu.com/view/1866754.htm