Mybatis源碼研究7:緩存的設計和實現

Mybatis源碼研究7:緩存的設計和實現

版權聲明:本文爲博主原創文章,未經博主容許不得轉載。 https://blog.csdn.net/u014723529/article/details/41288565

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

相關文章
相關標籤/搜索