diff --git a/docs/Mybatis/基础支持层/Mybatis-Cache.md b/docs/Mybatis/基础支持层/Mybatis-Cache.md new file mode 100644 index 0000000..512b1bc --- /dev/null +++ b/docs/Mybatis/基础支持层/Mybatis-Cache.md @@ -0,0 +1,319 @@ +# mybatis 缓存 +- Author: [HuiFer](https://github.com/huifer) +- Description: 该文介绍 mybatis Cache 源码 +- `org.apache.ibatis.cache.Cache` +```java +public interface Cache { + + String getId(); + + /** + * 放入数据 + */ + void putObject(Object key, Object value); + + /** + * 获取数据 + */ + Object getObject(Object key); + + /** + * 移除数据 + */ + Object removeObject(Object key); + + /** + * 清空数据 + */ + void clear(); + + /** + * 有多少缓存数据 + */ + int getSize(); + + /** + * 重入锁 + * @return A ReadWriteLock + */ + default ReadWriteLock getReadWriteLock() { + return null; + } + +} +``` + +- BlockingCache: 阻塞的缓存 +- FifoCache: 按对象进入缓存的顺序来移除它们。 +- LruCache: 最近最少使用的:移除最长时间不被使用的对象。 +- SoftCache: 软引用:移除基于垃圾回收器状态和软引用规则的对象 +- WeakCache: 弱引用:更积极地移除基于垃圾收集器状态和弱引用规则的对象。 + +## BlockingCache +- BlockingCache 内部使用了`ReentrantLock`来进行加锁开锁这个操作.在插入缓存时上锁,插入缓存后释放.请求缓存值得时候同理 +```java +public class BlockingCache implements Cache { + + private final Cache delegate; + /** + * 线程安全的map + */ + private final ConcurrentHashMap locks; + private long timeout; + + public BlockingCache(Cache delegate) { + this.delegate = delegate; + this.locks = new ConcurrentHashMap<>(); + } + + @Override + public String getId() { + return delegate.getId(); + } + + @Override + public int getSize() { + return delegate.getSize(); + } + + @Override + public void putObject(Object key, Object value) { + try { + delegate.putObject(key, value); + } finally { + releaseLock(key); + } + } + + @Override + public Object getObject(Object key) { + acquireLock(key); + Object value = delegate.getObject(key); + if (value != null) { + // 释放锁 + releaseLock(key); + } + return value; + } + + @Override + public Object removeObject(Object key) { + // despite of its name, this method is called only to release locks + releaseLock(key); + return null; + } + + @Override + public void clear() { + delegate.clear(); + } + + private ReentrantLock getLockForKey(Object key) { + return locks.computeIfAbsent(key, k -> new ReentrantLock()); + } + + /** + * 请求锁 + * @param key + */ + private void acquireLock(Object key) { + Lock lock = getLockForKey(key); + if (timeout > 0) { + try { + // 上锁 + boolean acquired = lock.tryLock(timeout, TimeUnit.MILLISECONDS); + if (!acquired) { + throw new CacheException("Couldn't get a lock in " + timeout + " for the key " + key + " at the cache " + delegate.getId()); + } + } catch (InterruptedException e) { + throw new CacheException("Got interrupted while trying to acquire lock for key " + key, e); + } + } else { + lock.lock(); + } + } + + /** + * 释放锁 + * @param key + */ + private void releaseLock(Object key) { + ReentrantLock lock = locks.get(key); + if (lock.isHeldByCurrentThread()) { + lock.unlock(); + } + } + + public long getTimeout() { + return timeout; + } + + public void setTimeout(long timeout) { + this.timeout = timeout; + } +} +``` + +## FifoCache +- 存储结构是`java.util.LinkedList` +```java +public class FifoCache implements Cache { + + private final Cache delegate; + /** + * 队列 + */ + private final Deque keyList; + private int size; + + 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) { + cycleKeyList(key); + delegate.putObject(key, value); + } + + @Override + public Object getObject(Object key) { + return delegate.getObject(key); + } + + @Override + public Object removeObject(Object key) { + return delegate.removeObject(key); + } + + @Override + public void clear() { + delegate.clear(); + keyList.clear(); + } + + /** + * 添加 key 删除最开始的一个 + * + * @param key + */ + private void cycleKeyList(Object key) { + keyList.addLast(key); + if (keyList.size() > size) { + Object oldestKey = keyList.removeFirst(); + delegate.removeObject(oldestKey); + } + } + +} +``` + +## LruCache +- 存储结构是`java.util.LinkedHashMap` +```java +/** + * Lru (least recently used) cache decorator. + * LRU 緩存策略 最近最少使用的:移除最长时间不被使用的对象。 + * + * @author Clinton Begin + */ +public class LruCache implements Cache { + + private final Cache delegate; + /** + * {@link LinkedHashMap} + */ + private Map keyMap; + private Object eldestKey; + + public LruCache(Cache delegate) { + this.delegate = delegate; + setSize(1024); + } + + @Override + public String getId() { + return delegate.getId(); + } + + @Override + public int getSize() { + return delegate.getSize(); + } + + /** + * 设置大小 + * + * @param size + */ + public void setSize(final int size) { + keyMap = new LinkedHashMap(size, .75F, true) { + private static final long serialVersionUID = 4267176411845948333L; + + @Override + protected boolean removeEldestEntry(Map.Entry eldest) { + // 数量超出预设值 执行 + boolean tooBig = size() > size; + if (tooBig) { +// 获取被移除的key + eldestKey = eldest.getKey(); + } + return tooBig; + } + }; + } + + @Override + public void putObject(Object key, Object value) { + delegate.putObject(key, value); + cycleKeyList(key); + } + + @Override + public Object getObject(Object key) { + keyMap.get(key); //touch + return delegate.getObject(key); + } + + @Override + public Object removeObject(Object key) { + return delegate.removeObject(key); + } + + @Override + public void clear() { + delegate.clear(); + keyMap.clear(); + } + + /** + * 删除最早的一个key + * @param key + */ + private void cycleKeyList(Object key) { + keyMap.put(key, key); + if (eldestKey != null) { + delegate.removeObject(eldestKey); + eldestKey = null; + } + } + +} +``` +