MyBatis的缓存

Mybatis默认的缓存接口是Cache,默认的实现是PerpetualCache,有一个HashMap的成员变量:

private Map cache =new HashMap<>();

所有的put和get都是往cache这个成员变量中操作,每个操作没有加锁,是个线程不安全的。

Mybatis还提供了几个修饰类作为缓存:

BlockingCache,FIFOCache,LoggingCache,LruCache,ScheduleCache,SerialezedCache,

SoftCache,SynchronizedCache,TransactionalCache,WeakCache。

BlockingCache

BlockingCache实现了Cache接口拥有一个Cache成员变量和一个锁的map

private final Cache    delegate;

private final ConcurrentHashMap     locks;

看get方法:

public Object getObject(Object key) {//取的时候加锁

  acquireLock(key);

Object value =delegate.getObject(key);

if (value !=null) {

releaseLock(key);

}

return value;

}

可以看出getObject的时候会加锁

FifoCache

借助private final Deque   keyList这个双向队列

put方法

public void putObject(Object key, Object value) {

cycleKeyList(key);

delegate.putObject(key, value);

}

private void cycleKeyList(Object key) {

keyList.addLast(key);

if (keyList.size() >size) {

Object oldestKey =keyList.removeFirst();

delegate.removeObject(oldestKey);

}

}

put的时候判断队列的大小是否大于给定的值1024,如果大于删除头结点,并从缓存中删除对应的key

LoggingCache

每次get的时候提供日志打印

@Override

public Object getObject(Object key) {

requests++;

final Object value =delegate.getObject(key);

if (value !=null) {

hits++;

}

if (log.isDebugEnabled()) {

log.debug("Cache Hit Ratio [" + getId() +"]: " + getHitRatio());

}

return value;

}

LruCache

借助于private Map  keyMap;实现为LinkedHashMap

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) {

eldestKey = eldest.getKey();

}

return tooBig;

}

};

removeEldestEntry为LinkedHahMap实现LRU算法的实现

put方法

public void putObject(Object key, Object value) {

delegate.putObject(key, value);

cycleKeyList(key);

}

private void cycleKeyList(Object key) {

keyMap.put(key, key);

if (eldestKey !=null) {

delegate.removeObject(eldestKey);

eldestKey =null;

}

}

每次putObject的时候查询是否有eldestKey ,有的话从缓存删除

ScheduledCache

有两个成员变量清除间隔clearInterval和上次清除时间lastClear

每次有getSize,getObject和putObject的时候,调用clearWhenStale

private boolean clearWhenStale() {

if (System.currentTimeMillis() -lastClear >clearInterval) {

clear();

return true;

}

return false;

}

判断是否到达清除间隔时间,到达的话调用clear,清除所有的缓存信息

@Override

public void clear() {

lastClear = System.currentTimeMillis();

delegate.clear();

}

SerializedCache

需要存入的对象实现Serializable接口

put方法:

@Override

public void putObject(Object key, Object object) {

if (object ==null || objectinstanceof Serializable) {

delegate.putObject(key, serialize((Serializable) object));

}else {

throw new CacheException("SharedCache failed to make a copy of a non-serializable object: " + object);

}

}

private byte[] serialize(Serializable value) {

try {

ByteArrayOutputStream bos =new ByteArrayOutputStream();

ObjectOutputStream oos =new ObjectOutputStream(bos);

oos.writeObject(value);

oos.flush();

oos.close();

return bos.toByteArray();

}catch (Exception e) {

throw new CacheException("Error serializing object.  Cause: " + e, e);

}

}

JAVA原生的序列化方式序列化后存入缓存

get的方法如下:

@Override

public Object getObject(Object key) {

Object object =delegate.getObject(key);

return object ==null ?null : deserialize((byte[]) object);

}

private Serializable deserialize(byte[] value) {

Serializable result;

try {

ByteArrayInputStream bis =new ByteArrayInputStream(value);

ObjectInputStream ois =new CustomObjectInputStream(bis);

result = (Serializable) ois.readObject();

ois.close();

}catch (Exception e) {

throw new CacheException("Error deserializing object.  Cause: " + e, e);

}

return result;

}

调用JAVA原生的反序列化方式反序列化出缓存的对象

SoftCache

借助双向队列hardLinksToAvoidGarbageCollection和ReferenceQueue实例queueOfGarbageCollectedEntries

以及一个软引用的子类SoftEntry

private static class SoftEntryextends SoftReference {

private final Objectkey;

SoftEntry(Object key, Object value, ReferenceQueue garbageCollectionQueue) {

super(value, garbageCollectionQueue);

this.key = key;

}

}

put的方法如下:

@Override

public void putObject(Object key, Object value) {

removeGarbageCollectedItems();

delegate.putObject(key,new SoftEntry(key, value,queueOfGarbageCollectedEntries));

}

把每个value变为一个软引用

removeGarbageCollectedItems:

private void removeGarbageCollectedItems() {

SoftEntry sv;

while ((sv = (SoftEntry)queueOfGarbageCollectedEntries.poll()) !=null) {

delegate.removeObject(sv.key);

}

}

你可能感兴趣的:(MyBatis的缓存)