一级缓存触发流程:
我们注意到这里一级缓存使用的是map结构来存储缓存,为何不用ConcurrentHashMap呢,因为sqlSession本身不是线程安全的,它不线程安全是由于JDBC的Connection对象本身也不是线程安全的,所以既然都不安全了,所以这里也没必要做线程安全的map结构。
我们来看看缓存的key里面有什么:
我们可以看到,有statementid,分页条件,查询语句内容,查询参数,环境(environment的id),这个也对应了缓存的命中场景的内容。
一级缓存的判断主要发生在BaseExecutor的query方法中,如下所示:
若找不到缓存则去查询数据查询。
题外话:什么时候清空缓存?
调用BaseExecutor的update方法的时候:
public int update(MappedStatement ms, Object parameter) throws SQLException {
ErrorContext.instance().resource(ms.getResource()).activity("executing an update").object(ms.getId());
if (closed) {
throw new ExecutorException("Executor was closed.");
}
clearLocalCache();
return doUpdate(ms, parameter);
}
调用BaseExecutor.query,判断是否第一次查询的时候,且配置了flushCache为true,即调用:
if (queryStack == 0 && ms.isFlushCacheRequired()) {
clearLocalCache();
}
调用BaseExecutor.query,查询后,缓存的作用域不是STATEMENT,这里必须要是第一次查询,子查询是不会清空缓存的。
if (configuration.getLocalCacheScope() == LocalCacheScope.STATEMENT) {
// issue #482
clearLocalCache();
}
调用BaseExecutor.commit或者rollback:
public void commit(boolean required) throws SQLException {
if (closed) {
throw new ExecutorException("Cannot commit, transaction is already closed");
}
clearLocalCache();
flushStatements();
if (required) {
transaction.commit();
}
}
public void rollback(boolean required) throws SQLException {
if (!closed) {
try {
clearLocalCache();
flushStatements(true);
} finally {
if (required) {
transaction.rollback();
}
}
}
}