成都网站建设设计

将想法与焦点和您一起共享

Mybatis中缓存的方式有哪些-创新互联

本篇文章给大家分享的是有关Mybatis中缓存的方式有哪些,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。

成都创新互联主要从事做网站、成都网站建设、网页设计、企业做网站、公司建网站等业务。立足成都服务三河,十多年网站建设经验,价格优惠、服务专业,欢迎来电咨询建站服务:13518219792

一级缓存

通过查看源码可知,一级缓存是绑定sqSsession中的,所以每次查询sqlSession不同就失效,相同的sqlSession可以使用一级缓存。

mybatis默认sqlsession:org.apache.ibatis.session.defaults.DefaultSqlSession

构造方法中传入executor(查询执行对象)

 public DefaultSqlSession(Configuration configuration, Executor executor, boolean autoCommit) {
  this.configuration = configuration;
  this.executor = executor;
  this.dirty = false;
  this.autoCommit = autoCommit;
 }

executor中携带一级缓存成员:

 protected BaseExecutor(Configuration configuration, Transaction transaction) {
  this.transaction = transaction;
  this.deferredLoads = new ConcurrentLinkedQueue<>();
  this.localCache = new PerpetualCache("LocalCache"); //默认一级缓存
  this.localOutputParameterCache = new PerpetualCache("LocalOutputParameterCache");
  this.closed = false;
  this.configuration = configuration;
  this.wrapper = this;
 }

查询使用一级缓存逻辑

org.apache.ibatis.executor.BaseExecutor.query()

 public  List query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
  ErrorContext.instance().resource(ms.getResource()).activity("executing a query").object(ms.getId());
  
  List list;
  try {
   queryStack++;
   	//localCache 一级缓存
   list = resultHandler == null ? (List) localCache.getObject(key) : null;
    //先从一级缓存中获取,key是通过sql语句生成
   if (list != null) {
    handleLocallyCachedOutputParameters(ms, key, parameter, boundSql);
   } else {
    // 如果缓存中没有 才从数据库查询
    list = queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql);
   }
  } finally {
   queryStack--;
  }
  return list;
 }

 //从数据库读取数据
 private  List queryFromDatabase(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
  List list;
  localCache.putObject(key, EXECUTION_PLACEHOLDER);
  try {
   list = doQuery(ms, parameter, rowBounds, resultHandler, boundSql);
  } finally {
   localCache.removeObject(key);//将一级缓存清除
  }
  localCache.putObject(key, list);//返回查询结果之前,先放入一级缓存 刷新
  if (ms.getStatementType() == StatementType.CALLABLE) {
   localOutputParameterCache.putObject(key, parameter);
  }
  return list;
 }

二级缓存

二级缓存mapper中的,默认是开启的,但需要在映射文件mapper.xml中添加标签


	

配置false可以关闭二级缓存

二级缓存的解析

org.apache.ibatis.builder.xml.XMLMapperBuilder

 private void configurationElement(XNode context) {
  try {
   //...
   cacheElement(context.evalNode("cache")); //解析cache标签
  } catch (Exception e) {
   throw new BuilderException("Error parsing Mapper XML. The XML location is '" + resource + "'. Cause: " + e, e);
  }
 }

 private void cacheElement(XNode context) {
  if (context != null) { // if hava cache tag 如果有cache标签才执行下面的逻辑
   String type = context.getStringAttribute("type", "PERPETUAL");
   Class typeClass = typeAliasRegistry.resolveAlias(type);
   String eviction = context.getStringAttribute("eviction", "LRU");
   Class evictionClass = typeAliasRegistry.resolveAlias(eviction);
   Long flushInterval = context.getLongAttribute("flushInterval");
   Integer size = context.getIntAttribute("size");
   boolean readWrite = !context.getBooleanAttribute("readOnly", false);
   boolean blocking = context.getBooleanAttribute("blocking", false);
   Properties props = context.getChildrenAsProperties();
   builderAssistant.useNewCache(typeClass, evictionClass, flushInterval, size, readWrite, blocking, props);//建立二级缓存
  }
 }

org.apache.ibatis.builder.MapperBuilderAssistant.useNewCache():

 public Cache useNewCache(Class typeClass,
   Class evictionClass,
   Long flushInterval,
   Integer size,
   boolean readWrite,
   boolean blocking,
   Properties props) {
  Cache cache = new CacheBuilder(currentNamespace)
    .implementation(valueOrDefault(typeClass, PerpetualCache.class))
    .addDecorator(valueOrDefault(evictionClass, LruCache.class))
    .clearInterval(flushInterval)
    .size(size)
    .readWrite(readWrite)
    .blocking(blocking)
    .properties(props)
    .build();
  configuration.addCache(cache);//二级缓存赋值,如果cache标签为空,不会执行此方法,currentCache为空
  currentCache = cache; 
  return cache;
 }

 在映射文件mapper中如果没有cache标签,不会执行上面的useNewCache方法,cache为null,就不会使用二级缓存(相当于失效)。

查询使用二级缓存逻辑

org.apache.ibatis.executor.CachingExecutor :

 @Override
 public  List query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql)
   throws SQLException {
  Cache cache = ms.getCache(); 
  if (cache != null) {//如果二级缓存对象不为空 尝试在二级缓存中获取(没有cache标签此对象就是空)
   flushCacheIfRequired(ms);
   if (ms.isUseCache() && resultHandler == null) {
    ensureNoOutParams(ms, boundSql);
    @SuppressWarnings("unchecked")
    List list = (List) tcm.getObject(cache, key); //从二级缓存中获取数据
    if (list == null) {
     list = delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql); //如果为空,使用delegate查询(BaseExecutor)
     tcm.putObject(cache, key, list); // 查询结果保存到二级缓存
    }
    return list;
   }
  }
  return delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
 }

二级缓存和一级缓存不用想,数据库的数据被修改是要清空缓存的,不然数据有误,至于怎么清空,是另一套逻辑了,mapper中的cache标签可以配置一些参数,比如缓存定期清空。

一级二级缓存先后顺序

mybatis默认是先查询二级缓存,没有,再查看一级缓存,都为空,最后查询数据库

以上就是Mybatis中缓存的方式有哪些,小编相信有部分知识点可能是我们日常工作会见到或用到的。希望你能通过这篇文章学到更多知识。更多详情敬请关注创新互联行业资讯频道。


网站栏目:Mybatis中缓存的方式有哪些-创新互联
当前URL:http://chengdu.cdxwcx.cn/article/codgih.html