缓存机制

mybatis系统中默认定义了两级缓存
一级缓存和二级缓存
默认情况下,只有一级缓存(SqlSession级别的缓存,也称为本地缓存)开启。
二级缓存需要手动开启和配置,它是基于namespace级别的缓存。
为了提高扩展性。mybatis定义了缓存接口Cache。我们可以通过实现Cache接口来自定义二级缓存。

一级缓存:本地缓存,SqlSession级别的缓存,一级缓存是一直开启的,
与数据库同一次会话期间查询到的数据会放在本地缓存中
以后如果需要获取相同的数据,直接从缓存中拿,没必要再去查询数据库

一级缓存失效情况(没有使用到当前一级缓存的情况,效果就是还需要向数据库发出查询语句)
1、使用不同的SqlSession,使用的缓存是不同的
2、SqlSession相同,查询条件不同(当前一级缓存中不存在)
3、SqlSession相同,两次查询之间执行增删改操作(这次增删改可能会对向前数据有影响,实际上增删改底层源码都是执行update方法,而在执行update方法的时候会清理本地缓存,最终执行JDBC的ps.execute())
4、SqlSession相同,手动清空缓存sqlSession.clearCache()

二级缓存:全局缓存,基于namespace级别的缓存,一个namespace对应一个二级缓存
工作机制:
一个会话,查询一条数据,这个数据就会被放在当前会话的一级缓存中
如果会话关闭,一级缓存中的数据会被保存到二级缓存中,新的会话查询信息,就可以参照二级缓存。
sqlSession =>StudentMapper=>Student
ClassInfoMapper===>ClassInfo
不同的namespace查出的数据会放在自己对应的缓存中(map中)
效果:数据会从二级缓存中获取,查出的数据会被默认先放在一级缓存中,只有会话提交或者关闭以后,一级缓存中的数据才会被转移到二级缓存中。

使用:
1、在全局配置文件中配置cacheEnabled=true,默认是开启的,建议都显示配置,避免版本升级造成配置改变。
2、在SQL映射配置文件中设置具体的缓存信息

<cache eviction="LRU" flushInterval="60000" readOnly="false" size="1024" type=""></cache>
	<!-- 
		eviction:缓存的回收策略,默认LRU
			LRU:最近最少使用,移除最长时间不被使用的对象
			FIFO:先进先出,按照对象进入缓存的顺序移除对象
			SOFT:软引用,移除基于垃圾回收器状态和软引用规则的对象
			WEAK:弱引用,更积极地移除基于垃圾回收器状态和若引用规则的对象
		flushInterval:缓存刷新间隔
			缓存多长时间清空一次,默认不清空,设置一个毫秒值
		readOnly:是否只读
			true:只读,mybatis认为所有从缓存中获取数据的操作都是只读操作,不会修改数据
					 mybatis为了加快获取速度,直接就会将数据在缓存中的引用交给用户。速度快,但是不安全
			false:非只读,mybatis觉得获取的数据可能会被修改,mybatis会利用序列化和反序列化的技术克隆一份新的数据给用户。速度慢,但是安全。
		size:设置存放缓存的大小,即存放多少数据
		type:缓存实现的全类名,用的默认的,如果设置,则表示使用自定义的缓存实现,实现Cache接口即可。
	 -->

3、JavaBean,即POJO对象需要实现序列化接口,Serializable

和缓存相关的设置/属性
1、cacheEnabled=“false”关闭的是二级缓存,不会关闭一级缓存
2、在每个select标签中都有useCache属性,影响的也是二级缓存,在全局启用二级缓存的情况下,在select标签中可以设置该条查询不使用二级缓存,useCache=“false”。

  @Override
  public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql)
      throws SQLException {
          //判断sql映射文件中是否配置二级缓存
    Cache cache = ms.getCache();
    if (cache != null) {
        //判断是否清空二级缓存,需要sql映射文件中是否配置二级缓存,并且select标签中flushCache='true',默认false
      flushCacheIfRequired(ms);
      //useCache是否为true,本条语句的结果被二级缓存缓存起来,也就是下面tcm.putObject(cache, key, list)
      if (ms.isUseCache() && resultHandler == null) {
        ensureNoOutParams(ms, parameterObject, boundSql);
        @SuppressWarnings("unchecked")
        //先去二级缓存拿,如果没有再执行delegate.<E> query,这里面会先从一级缓存拿,如果还是没有则直接从数据库查
        List<E> list = (List<E>) tcm.getObject(cache, key);
        if (list == null) {
          list = delegate.<E> query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
          tcm.putObject(cache, key, list); // issue #578 and #116
        }
        return list;
      }
    }
    return delegate.<E> query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
  }
  
  
  private void flushCacheIfRequired(MappedStatement ms) {
    Cache cache = ms.getCache();
    if (cache != null && ms.isFlushCacheRequired()) {      
      tcm.clear(cache);
    }
  }

3、每个增删改标签中,都有flushCache=“true”,默认清空缓存,这里会将一级缓存和二级缓存都清除(这里flushCache="true"实际上只影响二级缓存,但是增删改不管flushChache是否设置,都会清理一级缓存,但是在执行select时flushCache会影响一级和二级缓存,如果设置为true,则都会清理)。在select标签中中也有flushCache,但是默认false,不会清除缓存。
4、sqlSession.clearCache()只清除当前session的一级缓存
5、localCacheScope:本地缓存作用域(一级缓存),有SESSION和STATEMENT两个值,默认SESSION,如果是STATEMENT,则会清理一级缓存,可以使用此设置禁用一级缓存。

 if (configuration.getLocalCacheScope() == LocalCacheScope.STATEMENT) {
        // issue #482
        clearLocalCache();
      }

缓存机制:
在这里插入图片描述
查询顺序是先从二级缓存中查,如果二级缓存中没有再去一级缓存中查询,最后再去数据库。

chache-ref标签:引用缓存,namespace指定和哪个名称空间下的的缓存一样的配置。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值