mybatis的一级缓存、二级缓存的过期时间分析
对于mybatis的缓存,我们往往有这样两个疑问:一级缓存、二级缓存的过期时间是多少?后台是否有个线程在检测?针对这两个问题,见下面的分析:
1、一级缓存无过期时间,只有生命周期
(1)MyBatis在开启一个数据库会话时,会创建一个新的SqlSession对象,SqlSession对象中会有一个Executor对象,Executor对象中持有一个PerpetualCache对象,见下面代码。当会话结束时,SqlSession对象及其内部的Executor对象还有PerpetualCache对象也一并释放掉。
protected BaseExecutor(Configuration configuration, Transaction transaction) {
this.transaction = transaction;
this.deferredLoads = new ConcurrentLinkedQueue<DeferredLoad>();
this.localCache = new PerpetualCache("LocalCache");
this.localOutputParameterCache = new PerpetualCache("LocalOutputParameterCache");
this.closed = false;
this.configuration = configuration;
this.wrapper = this;
}
(2)如果SqlSession调用了close()方法,会释放掉一级缓存PerpetualCache对象,一级缓存将不可用;
(3)如果SqlSession调用了clearCache(),会清空PerpetualCache对象中的数据,但是该对象仍可使用;
(4)SqlSession中执行了任何一个更新操作,例如:update、delete、insert ,都会清空PerpetualCache对象的数据,但是该对象可以继续使用;
2、二级缓存有过期时间,但没有后台线程进行检测
需要注意的是,并不是key-value的过期时间,而是这个cache的过期时间,是flushInterval,意味着整个清空缓存cache,所以不需要后台线程去定时检测。
每当存取数据的时候,都有检测一下cache的生命时间,默认是1小时,如果这个cache存活了一个小时,那么将整个清空一下。
public class ScheduledCache implements Cache
{
private final Cache delegate;
protected long clearInterval;
protected long lastClear;
public ScheduledCache(Cache delegate)
{
this.delegate = delegate;
this.clearInterval = 60 * 60 * 1000;
this.lastClear = System.currentTimeMillis();
}
public void setClearInterval(long clearInterval)
{
this.clearInterval = clearInterval;
}
@Override
public String getId()
{
return delegate.getId();
}
@Override
public int getSize()
{
clearWhenStale();
return delegate.getSize();
}
@Override
public void putObject(Object key, Object object)
{
clearWhenStale();
delegate.putObject(key, object);
}
@Override
public Object getObject(Object key)
{
return clearWhenStale() ? null : delegate.getObject(key);
}
@Override
public Object removeObject(Object key)
{
clearWhenStale();
return delegate.removeObject(key);
}
@Override
public void clear()
{
lastClear = System.currentTimeMillis();
delegate.clear();
}
@Override
public ReadWriteLock getReadWriteLock()
{
return null;
}
@Override
public int hashCode()
{
return delegate.hashCode();
}
@Override
public boolean equals(Object obj)
{
return delegate.equals(obj);
}
private boolean clearWhenStale()
{
if (System.currentTimeMillis() - lastClear > clearInterval)
{
clear();
return true;
}
return false;
}
}