内射老阿姨1区2区3区4区_久久精品人人做人人爽电影蜜月_久久国产精品亚洲77777_99精品又大又爽又粗少妇毛片

Mybatis緩存模塊的示例分析

這篇文章給大家分享的是有關(guān)Mybatis緩存模塊的示例分析的內(nèi)容。小編覺(jué)得挺實(shí)用的,因此分享給大家做個(gè)參考,一起跟隨小編過(guò)來(lái)看看吧。

成都創(chuàng)新互聯(liá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ù)。

1 Cache 組件

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)??!   * 這是 Java8 的新特性??!只是平時(shí)開(kāi)發(fā)時(shí)很少用到?。?!   * ?。。。。。。。。。。。。。。。。。。。。。。。。。?nbsp;  */  default ReadWriteLock getReadWriteLock() {    return null;  }}

如下圖所示,Cache 接口 的實(shí)現(xiàn)類有很多,但大部分都是裝飾器,只有 PerpetualCache 提供了 Cache 接口 的基本實(shí)現(xiàn)。

Mybatis緩存模塊的示例分析

1.1 PerpetualCache

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è)組合后滿足一個(gè)特定的需求。

1.2 BlockingCache

BlockingCache 是阻塞版本的緩存裝飾器,它會(huì)保證只有一個(gè)線程到數(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è) 線程 A 在 BlockingCache 中未查找到 keyA 對(duì)應(yīng)的緩存項(xiàng)時(shí),線程 A 會(huì)獲取 keyA 對(duì)應(yīng)的鎖,這樣,線程 A 在后續(xù)查找 keyA 時(shí),其它線程會(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系列類 中新增的方法    // 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è) 線程 A 從數(shù)據(jù)庫(kù)中查找到 keyA 對(duì)應(yīng)的結(jié)果對(duì)象后,將結(jié)果對(duì)象放入到 BlockingCache 中,此時(shí) 線程 A 會(huì)釋放 keyA 對(duì)應(yīng)的鎖,喚醒阻塞在該鎖上的線程。其它線程即可從 BlockingCache 中獲取 keyA 對(duì)應(yīng)的數(shù)據(jù),而不是再次訪問(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)前線程持有    if (lock.isHeldByCurrentThread()) {      // 是,則釋放鎖      lock.unlock();    }  }

1.3 FifoCache 和 LruCache

在很多場(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) {    // 訪問(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();  }}

1.4 SoftCache 和 WeakCache

在分析 SoftCache 和 WeakCache 實(shí)現(xiàn)之前,我們?cè)贉亓?xí)一下 Java 提供的 4 種引用類型,強(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)引用的一種引用,它使用類 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)存緊張的情況才被回收。?虛引用 最弱的一種引用類型,由類 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 基本類似,唯一的區(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ù)和訪問(wèn)次數(shù)。在 LoggingCache.getObject()方法 中,會(huì)統(tǒng)計(jì)命中次數(shù)和訪問(wèn)次數(shù) 這兩個(gè)指標(biāo),井按照指定的日志輸出方式輸出命中率。

SynchronizedCache 通過(guò)在每個(gè)方法上添加 synchronized 關(guān)鍵字,為 Cache 添加了同步功能,有點(diǎn)類似于 JDK 中 Collections 的 SynchronizedCollection 內(nè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)行裝飾的話,每次從緩存中獲取同一 key 對(duì)應(yīng)的對(duì)象時(shí),得到的都是同一對(duì)象,任意一個(gè)線程修改該對(duì)象都會(huì)影響到其他線程,以及緩存中的對(duì)象。而使用 SerializedCache 每次從緩存中獲取數(shù)據(jù)時(shí),都會(huì)通過(guò)反序列化得到一個(gè)全新的對(duì)象。SerializedCache 使用的序列化方式是 Java 原生序列化。

2 CacheKey

在 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)表示緩存項(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、查詢結(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類型,直接返回 false    if (!(object instanceof CacheKey)) {      return false;    }    // 類型轉(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)題名稱:Mybatis緩存模塊的示例分析
標(biāo)題鏈接:http://m.rwnh.cn/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)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)

網(wǎng)站托管運(yùn)營(yíng)
盱眙县| 普定县| 马公市| 大余县| 高阳县| 徐州市| 崇文区| 永川市| 临朐县| 玉林市| 望城县| 兴山县| 吉隆县| 斗六市| 柯坪县| 同心县| 乌拉特前旗| 九江县| 阳高县| 广昌县| 唐山市| 兖州市| 南郑县| 舟山市| 舟曲县| 获嘉县| 武隆县| 万安县| 定结县| 鹿邑县| 正宁县| 黔西县| 阳谷县| 南澳县| 平遥县| 北川| 阿尔山市| 邵武市| 乌鲁木齐市| 固原市| 临清市|