這篇文章給大家分享的是有關(guān)Mybatis緩存模塊的示例分析的內(nèi)容。小編覺(jué)得挺實(shí)用的,因此分享給大家做個(gè)參考,一起跟隨小編過(guò)來(lái)看看吧。
成都創(chuàng)新互聯(lián)專(zhuān)注于靖安網(wǎng)站建設(shè)服務(wù)及定制,我們擁有豐富的企業(yè)做網(wǎng)站經(jīng)驗(yàn)。 熱誠(chéng)為您提供靖安營(yíng)銷(xiāo)型網(wǎng)站建設(shè),靖安網(wǎng)站制作、靖安網(wǎng)頁(yè)設(shè)計(jì)、靖安網(wǎng)站官網(wǎng)定制、成都微信小程序服務(wù),打造靖安網(wǎng)絡(luò)公司原創(chuàng)品牌,更為您提供靖安網(wǎng)站排名全網(wǎng)營(yíng)銷(xiāo)落地服務(wù)。
MyBatis 中緩存模塊相關(guān)的代碼位于 org.apache.ibatis.cache 包 下,其中 Cache 接口 是緩存模塊中最核心的接口,它定義了所有緩存的基本行為。
public interface Cache { /** * 獲取當(dāng)前緩存的 Id */ String getId(); /** * 存入緩存的 key 和 value,key 一般為 CacheKey對(duì)象 */ void putObject(Object key, Object value); /** * 根據(jù) key 獲取緩存值 */ Object getObject(Object key); /** * 刪除指定的緩存項(xiàng) */ Object removeObject(Object key); /** * 清空緩存 */ void clear(); /** * 獲取緩存的大小 */ int getSize(); /** * ?。。。。。。。。。。。。。。。。。。。。。。。。?! * 獲取讀寫(xiě)鎖,可以看到,這個(gè)接口方法提供了默認(rèn)的實(shí)現(xiàn)?。?nbsp; * 這是 Java8 的新特性??!只是平時(shí)開(kāi)發(fā)時(shí)很少用到!??! * ?。。。。。。。。。。。。。。。。。。。。。。。。?! */ default ReadWriteLock getReadWriteLock() { return null; }}
如下圖所示,Cache 接口 的實(shí)現(xiàn)類(lèi)有很多,但大部分都是裝飾器,只有 PerpetualCache 提供了 Cache 接口 的基本實(shí)現(xiàn)。
PerpetualCache(Perpetual:永恒的,持續(xù)的)在緩存模塊中扮演著被裝飾的角色,其實(shí)現(xiàn)比較簡(jiǎn)單,底層使用 HashMap 記錄緩存項(xiàng),也是通過(guò)該 HashMap 對(duì)象 的方法實(shí)現(xiàn)的 Cache 接口 中定義的相應(yīng)方法。
public class PerpetualCache implements Cache { // Cache對(duì)象 的唯一標(biāo)識(shí) private final String id; // 其所有的緩存功能實(shí)現(xiàn),都是基于 JDK 的 HashMap 提供的方法 private Map<Object, Object> cache = new HashMap<>(); public PerpetualCache(String id) { this.id = id; } @Override public String getId() { return id; } @Override public int getSize() { return cache.size(); } @Override public void putObject(Object key, Object value) { cache.put(key, value); } @Override public Object getObject(Object key) { return cache.get(key); } @Override public Object removeObject(Object key) { return cache.remove(key); } @Override public void clear() { cache.clear(); } /** * 其重寫(xiě)了 Object 中的 equals() 和 hashCode()方法,兩者都只關(guān)心 id字段 */ @Override 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()); } @Override public int hashCode() { if (getId() == null) { throw new CacheException("Cache instances require an ID."); } return getId().hashCode(); }}
下面來(lái)看一下 cache.decorators 包 下提供的裝飾器,它們都直接實(shí)現(xiàn)了 Cache 接口,扮演著裝飾器的角色。這些裝飾器會(huì)在 PerpetualCache 的基礎(chǔ)上提供一些額外的功能,通過(guò)多個(gè)組合后滿(mǎn)足一個(gè)特定的需求。
BlockingCache 是阻塞版本的緩存裝飾器,它會(huì)保證只有一個(gè)線(xiàn)程到數(shù)據(jù)庫(kù)中查找指定 key 對(duì)應(yīng)的數(shù)據(jù)。
public class BlockingCache implements Cache { // 阻塞超時(shí)時(shí)長(zhǎng) private long timeout; // 持有的被裝飾者 private final Cache delegate; // 每個(gè) key 都有其對(duì)應(yīng)的 ReentrantLock鎖對(duì)象 private final ConcurrentHashMap<Object, ReentrantLock> locks; // 初始化 持有的持有的被裝飾者 和 鎖集合 public BlockingCache(Cache delegate) { this.delegate = delegate; this.locks = new ConcurrentHashMap<>(); }}
假設(shè) 線(xiàn)程 A 在 BlockingCache 中未查找到 keyA 對(duì)應(yīng)的緩存項(xiàng)時(shí),線(xiàn)程 A 會(huì)獲取 keyA 對(duì)應(yīng)的鎖,這樣,線(xiàn)程 A 在后續(xù)查找 keyA 時(shí),其它線(xiàn)程會(huì)被阻塞。
// 根據(jù) key 獲取鎖對(duì)象,然后上鎖 private void acquireLock(Object key) { // 獲取 key 對(duì)應(yīng)的鎖對(duì)象 Lock lock = getLockForKey(key); // 獲取鎖,帶超時(shí)時(shí)長(zhǎng) if (timeout > 0) { try { boolean acquired = lock.tryLock(timeout, TimeUnit.MILLISECONDS); if (!acquired) { // 超時(shí),則拋出異常 throw new CacheException("Couldn't get a lock in " + timeout + " for the key " + key + " at the cache " + delegate.getId()); } } catch (InterruptedException e) { // 如果獲取鎖失敗,則阻塞一段時(shí)間 throw new CacheException("Got interrupted while trying to acquire lock for key " + key, e); } } else { // 上鎖 lock.lock(); } } private ReentrantLock getLockForKey(Object key) { // Java8 新特性,Map系列類(lèi) 中新增的方法 // V computeIfAbsent(K key, Function<? super K, ? extends V> mappingFunction) // 表示,若 key 對(duì)應(yīng)的 value 為空,則將第二個(gè)參數(shù)的返回值存入該 Map集合 并返回 return locks.computeIfAbsent(key, k -> new ReentrantLock()); }
假設(shè) 線(xiàn)程 A 從數(shù)據(jù)庫(kù)中查找到 keyA 對(duì)應(yīng)的結(jié)果對(duì)象后,將結(jié)果對(duì)象放入到 BlockingCache 中,此時(shí) 線(xiàn)程 A 會(huì)釋放 keyA 對(duì)應(yīng)的鎖,喚醒阻塞在該鎖上的線(xiàn)程。其它線(xiàn)程即可從 BlockingCache 中獲取 keyA 對(duì)應(yīng)的數(shù)據(jù),而不是再次訪(fǎng)問(wèn)數(shù)據(jù)庫(kù)。
@Override public void putObject(Object key, Object value) { try { // 存入 key 和其對(duì)應(yīng)的緩存項(xiàng) delegate.putObject(key, value); } finally { // 最后釋放鎖 releaseLock(key); } } private void releaseLock(Object key) { ReentrantLock lock = locks.get(key); // 鎖是否被當(dāng)前線(xiàn)程持有 if (lock.isHeldByCurrentThread()) { // 是,則釋放鎖 lock.unlock(); } }
在很多場(chǎng)景中,為了控制緩存的大小,系統(tǒng)需要按照一定的規(guī)則清理緩存。FifoCache 是先入先出版本的裝飾器,當(dāng)向緩存添加數(shù)據(jù)時(shí),如果緩存項(xiàng)的個(gè)數(shù)已經(jīng)達(dá)到上限,則會(huì)將緩存中最老(即最早進(jìn)入緩存)的緩存項(xiàng)刪除。
public class FifoCache implements Cache { // 被裝飾對(duì)象 private final Cache delegate; // 用一個(gè) FIFO 的隊(duì)列記錄 key 的順序,其具體實(shí)現(xiàn)為 LinkedList private final Deque<Object> keyList; // 決定了緩存的容量上限 private int size; // 國(guó)際慣例,通過(guò)構(gòu)造方法初始化自己的屬性,緩存容量上限默認(rèn)為 1024個(gè) public FifoCache(Cache delegate) { this.delegate = delegate; this.keyList = new LinkedList<>(); this.size = 1024; } @Override public String getId() { return delegate.getId(); } @Override public int getSize() { return delegate.getSize(); } public void setSize(int size) { this.size = size; } @Override public void putObject(Object key, Object value) { // 存儲(chǔ)緩存項(xiàng)之前,先在 keyList 中注冊(cè) cycleKeyList(key); // 存儲(chǔ)緩存項(xiàng) delegate.putObject(key, value); } private void cycleKeyList(Object key) { // 在 keyList隊(duì)列 中注冊(cè)要添加的 key keyList.addLast(key); // 如果注冊(cè)這個(gè) key 會(huì)超出容積上限,則把最老的一個(gè)緩存項(xiàng)清除掉 if (keyList.size() > size) { Object oldestKey = keyList.removeFirst(); delegate.removeObject(oldestKey); } } @Override public Object getObject(Object key) { return delegate.getObject(key); } @Override public Object removeObject(Object key) { return delegate.removeObject(key); } // 除了清理緩存項(xiàng),還要清理 key 的注冊(cè)列表 @Override public void clear() { delegate.clear(); keyList.clear(); }}
LruCache 是按照"近期最少使用算法"(Least Recently Used, LRU)進(jìn)行緩存清理的裝飾器,在需要清理緩存時(shí),它會(huì)清除最近最少使用的緩存項(xiàng)。
public class LruCache implements Cache { // 被裝飾者 private final Cache delegate; // 這里使用的是 LinkedHashMap,它繼承了 HashMap,但它的元素是有序的 private Map<Object, Object> keyMap; // 最近最少被使用的緩存項(xiàng)的 key private Object eldestKey; // 國(guó)際慣例,構(gòu)造方法中進(jìn)行屬性初始化 public LruCache(Cache delegate) { this.delegate = delegate; // 這里初始化了 keyMap,并定義了 eldestKey 的取值規(guī)則 setSize(1024); } public void setSize(final int size) { // 初始化 keyMap,同時(shí)指定該 Map 的初始容積及加載因子,第三個(gè)參數(shù)true 表示 該LinkedHashMap // 記錄的順序是 accessOrder,即,LinkedHashMap.get()方法 會(huì)改變其中元素的順序 keyMap = new LinkedHashMap<Object, Object>(size, .75F, true) { private static final long serialVersionUID = 4267176411845948333L; // 當(dāng)調(diào)用 LinkedHashMap.put()方法 時(shí),該方法會(huì)被調(diào)用 @Override protected boolean removeEldestEntry(Map.Entry<Object, Object> eldest) { boolean tooBig = size() > size; if (tooBig) { // 當(dāng)已達(dá)到緩存上限,更新 eldestKey字段,后面將其刪除 eldestKey = eldest.getKey(); } return tooBig; } }; } // 存儲(chǔ)緩存項(xiàng) @Override public void putObject(Object key, Object value) { delegate.putObject(key, value); // 記錄緩存項(xiàng)的 key,超出容量則清除最久未使用的緩存項(xiàng) cycleKeyList(key); } private void cycleKeyList(Object key) { keyMap.put(key, key); // eldestKey 不為空,則表示已經(jīng)達(dá)到緩存上限 if (eldestKey != null) { // 清除最久未使用的緩存 delegate.removeObject(eldestKey); // 制空 eldestKey = null; } } @Override public Object getObject(Object key) { // 訪(fǎng)問(wèn) key元素 會(huì)改變?cè)撛卦?nbsp;LinkedHashMap 中的順序 keyMap.get(key); //touch return delegate.getObject(key); } @Override public String getId() { return delegate.getId(); } @Override public int getSize() { return delegate.getSize(); } @Override public Object removeObject(Object key) { return delegate.removeObject(key); } @Override public void clear() { delegate.clear(); keyMap.clear(); }}
在分析 SoftCache 和 WeakCache 實(shí)現(xiàn)之前,我們?cè)贉亓?xí)一下 Java 提供的 4 種引用類(lèi)型,強(qiáng)引用 StrongReference、軟引用 SoftReference、弱引用 WeakReference 和虛引用 PhantomReference。
?強(qiáng)引用 平時(shí)用的最多的,如 Object obj = new Object(),新建的 Object 對(duì)象 就是被強(qiáng)引用的。如果一個(gè)對(duì)象被強(qiáng)引用,即使是 JVM 內(nèi)存空間不足,要拋出 OutOfMemoryError 異常,GC 也絕不會(huì)回收該對(duì)象。?軟引用 僅次于強(qiáng)引用的一種引用,它使用類(lèi) SoftReference 來(lái)表示。當(dāng) JVM 內(nèi)存不足時(shí),GC 會(huì)回收那些只被軟引用指向的對(duì)象,從而避免內(nèi)存溢出。軟引用適合引用那些可以通過(guò)其他方式恢復(fù)的對(duì)象,例如, 數(shù)據(jù)庫(kù)緩存中的對(duì)象就可以從數(shù)據(jù)庫(kù)中恢復(fù),所以軟引用可以用來(lái)實(shí)現(xiàn)緩存,下面要介紹的 SoftCache 就是通過(guò)軟引用實(shí)現(xiàn)的。
另外,由于在程序使用軟引用之前的某個(gè)時(shí)刻,其所指向的對(duì)象可能己經(jīng)被 GC 回收掉了,所以通過(guò) Reference.get()方法 來(lái)獲取軟引用所指向的對(duì)象時(shí),總是要通過(guò)檢查該方法返回值是否為 null,來(lái)判斷被軟引用的對(duì)象是否還存活。?弱引用 弱引用使用 WeakReference 表示,它不會(huì)阻止所引用的對(duì)象被 GC 回收。在 JVM 進(jìn)行垃圾回收時(shí),如果指向一個(gè)對(duì)象的所有引用都是弱引用,那么該對(duì)象會(huì)被回收。所以,只被弱引用所指向的對(duì)象,其生存周期是 兩次 GC 之間 的這段時(shí)間,而只被軟引用所指向的對(duì)象可以經(jīng)歷多次 GC,直到出現(xiàn)內(nèi)存緊張的情況才被回收。?虛引用 最弱的一種引用類(lèi)型,由類(lèi) PhantomReference 表示。虛引用可以用來(lái)實(shí)現(xiàn)比較精細(xì)的內(nèi)存使用控制,但很少使用。?引用隊(duì)列(ReferenceQueue ) 很多場(chǎng)景下,我們的程序需要在一個(gè)對(duì)象被 GC 時(shí)得到通知,引用隊(duì)列就是用于收集這些信息的隊(duì)列。在創(chuàng)建 SoftReference 對(duì)象 時(shí),可以為其關(guān)聯(lián)一個(gè)引用隊(duì)列,當(dāng) SoftReference 所引用的對(duì)象被 GC 時(shí), JVM 就會(huì)將該 SoftReference 對(duì)象 添加到與之關(guān)聯(lián)的引用隊(duì)列中。當(dāng)需要檢測(cè)這些通知信息時(shí),就可以從引用隊(duì)列中獲取這些 SoftReference 對(duì)象。不僅是 SoftReference,弱引用和虛引用都可以關(guān)聯(lián)相應(yīng)的隊(duì)列。
現(xiàn)在來(lái)看一下 SoftCache 的具體實(shí)現(xiàn)。
public class SoftCache implements Cache { // 這里使用了 LinkedList 作為容器,在 SoftCache 中,最近使用的一部分緩存項(xiàng)不會(huì)被 GC // 這是通過(guò)將其 value 添加到 hardLinksToAvoidGarbageCollection集合 實(shí)現(xiàn)的(即,有強(qiáng)引用指向其value) private final Deque<Object> hardLinksToAvoidGarbageCollection; // 引用隊(duì)列,用于記錄已經(jīng)被 GC 的緩存項(xiàng)所對(duì)應(yīng)的 SoftEntry對(duì)象 private final ReferenceQueue<Object> queueOfGarbageCollectedEntries; // 持有的被裝飾者 private final Cache delegate; // 強(qiáng)連接的個(gè)數(shù),默認(rèn)為 256 private int numberOfHardLinks; // 構(gòu)造方法進(jìn)行屬性的初始化 public SoftCache(Cache delegate) { this.delegate = delegate; this.numberOfHardLinks = 256; this.hardLinksToAvoidGarbageCollection = new LinkedList<>(); this.queueOfGarbageCollectedEntries = new ReferenceQueue<>(); } private static class SoftEntry extends SoftReference<Object> { private final Object key; SoftEntry(Object key, Object value, ReferenceQueue<Object> garbageCollectionQueue) { // 指向 value 的引用是軟引用,并且關(guān)聯(lián)了 引用隊(duì)列 super(value, garbageCollectionQueue); // 強(qiáng)引用 this.key = key; } } @Override public void putObject(Object key, Object value) { // 清除已經(jīng)被 GC 的緩存項(xiàng) removeGarbageCollectedItems(); // 添加緩存 delegate.putObject(key, new SoftEntry(key, value, queueOfGarbageCollectedEntries)); } private void removeGarbageCollectedItems() { SoftEntry sv; // 遍歷 queueOfGarbageCollectedEntries集合,清除已經(jīng)被 GC 的緩存項(xiàng) value while ((sv = (SoftEntry) queueOfGarbageCollectedEntries.poll()) != null) { delegate.removeObject(sv.key); } } @Override public Object getObject(Object key) { Object result = null; @SuppressWarnings("unchecked") // assumed delegate cache is totally managed by this cache // 用一個(gè)軟引用指向 key 對(duì)應(yīng)的緩存項(xiàng) SoftReference<Object> softReference = (SoftReference<Object>) delegate.getObject(key); // 檢測(cè)緩存中是否有對(duì)應(yīng)的緩存項(xiàng) if (softReference != null) { // 獲取 softReference 引用的 value result = softReference.get(); // 如果 softReference 引用的對(duì)象已經(jīng)被 GC,則從緩存中清除對(duì)應(yīng)的緩存項(xiàng) if (result == null) { delegate.removeObject(key); } else { synchronized (hardLinksToAvoidGarbageCollection) { // 將緩存項(xiàng)的 value 添加到 hardLinksToAvoidGarbageCollection集合 中保存 hardLinksToAvoidGarbageCollection.addFirst(result); // 如果 hardLinksToAvoidGarbageCollection 的容積已經(jīng)超過(guò) numberOfHardLinks // 則將最老的緩存項(xiàng)從 hardLinksToAvoidGarbageCollection 中清除,F(xiàn)IFO if (hardLinksToAvoidGarbageCollection.size() > numberOfHardLinks) { hardLinksToAvoidGarbageCollection.removeLast(); } } } } return result; } @Override public Object removeObject(Object key) { // 清除指定的緩存項(xiàng)之前,也會(huì)先清理被 GC 的緩存項(xiàng) removeGarbageCollectedItems(); return delegate.removeObject(key); } @Override public void clear() { synchronized (hardLinksToAvoidGarbageCollection) { // 清理強(qiáng)引用集合 hardLinksToAvoidGarbageCollection.clear(); } // 清理被 GC 的緩存項(xiàng) removeGarbageCollectedItems(); // 清理最底層的緩存項(xiàng) delegate.clear(); } @Override public String getId() { return delegate.getId(); } @Override public int getSize() { removeGarbageCollectedItems(); return delegate.getSize(); } public void setSize(int size) { this.numberOfHardLinks = size; }}
WeakCache 的實(shí)現(xiàn)與 SoftCache 基本類(lèi)似,唯一的區(qū)別在于其中使用 WeakEntry(繼承了 WeakReference)封裝真正的 value 對(duì)象,其他實(shí)現(xiàn)完全一樣。
另外,還有 ScheduledCache、LoggingCache、SynchronizedCache、SerializedCache 等。ScheduledCache 是周期性清理緩存的裝飾器,它的 clearInterval 字段 記錄了兩次緩存清理之間的時(shí)間間隔,默認(rèn)是一小時(shí),lastClear 字段 記錄了最近一次清理的時(shí)間戳。ScheduledCache 的 getObject()、putObject()、removeObject() 等核心方法,在執(zhí)行時(shí)都會(huì)根據(jù)這兩個(gè)字段檢測(cè)是否需要進(jìn)行清理操作,清理操作會(huì)清空緩存中所有緩存項(xiàng)。
LoggingCache 在 Cache 的基礎(chǔ)上提供了日志功能,它通過(guò) hit 字段 和 request 字段 記錄了 Cache 的命中次數(shù)和訪(fǎng)問(wèn)次數(shù)。在 LoggingCache.getObject()方法 中,會(huì)統(tǒng)計(jì)命中次數(shù)和訪(fǎng)問(wèn)次數(shù) 這兩個(gè)指標(biāo),井按照指定的日志輸出方式輸出命中率。
SynchronizedCache 通過(guò)在每個(gè)方法上添加 synchronized 關(guān)鍵字,為 Cache 添加了同步功能,有點(diǎn)類(lèi)似于 JDK 中 Collections 的 SynchronizedCollection 內(nèi)部類(lèi)。
SerializedCache 提供了將 value 對(duì)象 序列化的功能。SerializedCache 在添加緩存項(xiàng)時(shí),會(huì)將 value 對(duì)應(yīng)的 Java 對(duì)象 進(jìn)行序列化,井將序列化后的 byte[]數(shù)組 作為 value 存入緩存 。SerializedCache 在獲取緩存項(xiàng)時(shí),會(huì)將緩存項(xiàng)中的 byte[]數(shù)組 反序列化成 Java 對(duì)象。不使用 SerializedCache 裝飾器 進(jìn)行裝飾的話(huà),每次從緩存中獲取同一 key 對(duì)應(yīng)的對(duì)象時(shí),得到的都是同一對(duì)象,任意一個(gè)線(xiàn)程修改該對(duì)象都會(huì)影響到其他線(xiàn)程,以及緩存中的對(duì)象。而使用 SerializedCache 每次從緩存中獲取數(shù)據(jù)時(shí),都會(huì)通過(guò)反序列化得到一個(gè)全新的對(duì)象。SerializedCache 使用的序列化方式是 Java 原生序列化。
在 Cache 中唯一確定一個(gè)緩存項(xiàng),需要使用緩存項(xiàng)的 key 進(jìn)行比較,MyBatis 中因?yàn)樯婕?動(dòng)態(tài) SQL 等多方面因素, 其緩存項(xiàng)的 key 不能僅僅通過(guò)一個(gè) String 表示,所以 MyBatis 提供了 CacheKey 類(lèi) 來(lái)表示緩存項(xiàng)的 key,在一個(gè) CacheKey 對(duì)象 中可以封裝多個(gè)影響緩存項(xiàng)的因素。CacheKey 中可以添加多個(gè)對(duì)象,由這些對(duì)象共同確定兩個(gè) CacheKey 對(duì)象 是否相同。
public class CacheKey implements Cloneable, Serializable { private static final long serialVersionUID = 1146682552656046210L; public static final CacheKey NULL_CACHE_KEY = new NullCacheKey(); private static final int DEFAULT_MULTIPLYER = 37; private static final int DEFAULT_HASHCODE = 17; // 參與計(jì)算hashcode,默認(rèn)值DEFAULT_MULTIPLYER = 37 private final int multiplier; // 當(dāng)前CacheKey對(duì)象的hashcode,默認(rèn)值DEFAULT_HASHCODE = 17 private int hashcode; // 校驗(yàn)和 private long checksum; private int count; // 由該集合中的所有元素 共同決定兩個(gè)CacheKey對(duì)象是否相同,一般會(huì)使用一下四個(gè)元素 // MappedStatement的id、查詢(xún)結(jié)果集的范圍參數(shù)(RowBounds的offset和limit) // SQL語(yǔ)句(其中可能包含占位符"?")、SQL語(yǔ)句中占位符的實(shí)際參數(shù) private List<Object> updateList; // 構(gòu)造方法初始化屬性 public CacheKey() { this.hashcode = DEFAULT_HASHCODE; this.multiplier = DEFAULT_MULTIPLYER; this.count = 0; this.updateList = new ArrayList<>(); } public CacheKey(Object[] objects) { this(); updateAll(objects); } public void update(Object object) { int baseHashCode = object == null ? 1 : ArrayUtil.hashCode(object); // 重新計(jì)算count、checksum和hashcode的值 count++; checksum += baseHashCode; baseHashCode *= count; hashcode = multiplier * hashcode + baseHashCode; // 將object添加到updateList集合 updateList.add(object); } public int getUpdateCount() { return updateList.size(); } public void updateAll(Object[] objects) { for (Object o : objects) { update(o); } } /** * CacheKey重寫(xiě)了 equals() 和 hashCode()方法,這兩個(gè)方法使用上面介紹 * 的 count、checksum、hashcode、updateList 比較兩個(gè) CacheKey對(duì)象 是否相同 */ @Override public boolean equals(Object object) { // 如果為同一對(duì)象,直接返回 true if (this == object) { return true; } // 如果 object 都不是 CacheKey類(lèi)型,直接返回 false if (!(object instanceof CacheKey)) { return false; } // 類(lèi)型轉(zhuǎn)換一下 final CacheKey cacheKey = (CacheKey) object; // 依次比較 hashcode、checksum、count,如果不等,直接返回 false if (hashcode != cacheKey.hashcode) { return false; } if (checksum != cacheKey.checksum) { return false; } if (count != cacheKey.count) { return false; } // 比較 updateList 中的元素是否相同,不同直接返回 false for (int i = 0; i < updateList.size(); i++) { Object thisObject = updateList.get(i); Object thatObject = cacheKey.updateList.get(i); if (!ArrayUtil.equals(thisObject, thatObject)) { return false; } } return true; } @Override public int hashCode() { return hashcode; } @Override public String toString() { StringJoiner returnValue = new StringJoiner(":"); returnValue.add(String.valueOf(hashcode)); returnValue.add(String.valueOf(checksum)); updateList.stream().map(ArrayUtil::toString).forEach(returnValue::add); return returnValue.toString(); } @Override public CacheKey clone() throws CloneNotSupportedException { CacheKey clonedCacheKey = (CacheKey) super.clone(); clonedCacheKey.updateList = new ArrayList<>(updateList); return clonedCacheKey; }}
感謝各位的閱讀!關(guān)于“Mybatis緩存模塊的示例分析”這篇文章就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,讓大家可以學(xué)到更多知識(shí),如果覺(jué)得文章不錯(cuò),可以把它分享出去讓更多的人看到吧!
標(biāo)題名稱(chēng):Mybatis緩存模塊的示例分析
標(biāo)題鏈接:http://aaarwkj.com/article12/iggegc.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供服務(wù)器托管、營(yíng)銷(xiāo)型網(wǎng)站建設(shè)、Google、外貿(mào)網(wǎng)站建設(shè)、網(wǎng)站導(dǎo)航、品牌網(wǎng)站制作
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶(hù)投稿、用戶(hù)轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀(guān)點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話(huà):028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)