mybatis二级缓存工作机制

mybatis二级缓存工作机制

在mybatis的主配置文件中,启动二级缓存配置
    <settings>
        <setting name="cacheEnabled" value="true"/> 
    </settings>

    这个配置会再以后生成Executor的时候使用CachingExecutor而非 BaseExecutor

    然后在映射的xml配置文件如UserMapper.xml中 对该实体启用缓存,简单点写直接添加
<cache/>
即可。至此配置完成。


    在完成以上配置之后,对缓存进行测试
测试的核心代码
SqlSession session = sqlSessionFactory.openSession();
List<User> allUsers =  session.selectList("com.test.model.User.queryUserByName", "%test%", new RowBounds(1, 1));
session.commit();
List<User> allUsers3 = sqlSessionFactory.openSession().selectList("com.test.model.User.queryUserByName", "%test%", new RowBounds(1, 1));

    理论上将,这种方式查询数据请求,在mybatis中肯定是可以直接从二级缓存中取数据的。
    请看如下的图(网上找的,觉得还不错)。

mybatis二级缓存工作机制_第1张图片


    其中CachingExecutor类的query方法
public List query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {
    if (ms != null) {
      Cache cache = ms.getCache();
      if (cache != null) {
        flushCacheIfRequired(ms);
        cache.getReadWriteLock().readLock().lock();
        try {
          if (ms.isUseCache() && resultHandler == null) {
            CacheKey key = createCacheKey(ms, parameterObject, rowBounds);
            final List cachedList = (List) cache.getObject(key);
            if (cachedList != null) {
              return cachedList;
            } else {
              List list = delegate.query(ms, parameterObject, rowBounds, resultHandler);
              tcm.putObject(cache, key, list);
              return list;
            }
          } else {
            return delegate.query(ms, parameterObject, rowBounds, resultHandler);
          }
        } finally {
          cache.getReadWriteLock().readLock().unlock();
        }
      }
    }
    return delegate.query(ms, parameterObject, rowBounds, resultHandler);
  }

    查询请求来的时候,会首先从MappedStatement中取出缓存实例Cache,若开启了二级缓存的,则先从二级缓存中查找数据,找到即直接返回结果,若没有找到,则使用delegate(叫做代理业好,装饰器也好)所代理的查询(此处为BaseExecutor)来进行查询,代理的具体查询就不说了,不是本文的重点。结合上图以及代码,可以看出tcm.putObject(cache, key, list);这句话是将查询处理的结果放入缓存,其中tcm是在CachingExecutor中定义的private TransactionalCacheManager tcm = new TransactionalCacheManager();

    然后我们查看TransactionalCacheManager的putObject(cache, key, list)方法,如下
public class TransactionalCacheManager {
	private Map<Cache, TransactionalCache> transactionalCaches = new HashMap<Cache, TransactionalCache>();

  
  public void putObject(Cache cache, CacheKey key, Object value) {
    getTransactionalCache(cache).putObject(key, value);
  }

}


    继续查看TransactionalCache的源码,可以看到,在TransactionalCache的putObject(Object key, Object object)方法中,并不是直接将结果集合放入缓存中,而是加入到一个队列中,这个队列会再发起这次请求的SqlSession提交(commit)或关闭(close)的时候,调用到TransactionalCache的commit方法,从而调用到内部类AddEntry的commit方法,将结果集合存放到缓存中。
public class TransactionalCache implements Cache {
  private Cache delegate;
  private Map<Object, AddEntry> entriesToAddOnCommit;

public void putObject(Object key, Object object) {
    entriesToRemoveOnCommit.remove(key);
    entriesToAddOnCommit.put(key, new AddEntry(delegate, key, object));
  }

 public void commit() {
    delegate.getReadWriteLock().writeLock().lock();
    try {
      if (clearOnCommit) {
        delegate.clear();
      } else {
        for (RemoveEntry entry : entriesToRemoveOnCommit.values()) {
          entry.commit();
        }
      }
      for (AddEntry entry : entriesToAddOnCommit.values()) {
        entry.commit();
      }
      reset();
    } finally {
      delegate.getReadWriteLock().writeLock().unlock();
    }
  }


private static class AddEntry {
    private Cache cache;
    private Object key;
    private Object value;

    public AddEntry(Cache cache, Object key, Object value) {
      this.cache = cache;
      this.key = key;
      this.value = value;
    }

    public void commit() {
      cache.putObject(key, value);
    }
  }

}


    下图为将结果集合存入缓存的过程。

mybatis二级缓存工作机制_第2张图片

你可能感兴趣的:(cache,mybatis)