Mybatis-一级缓存

Mybatis有两级缓存,一级缓存是在同一个SqlSession中有效,两次完全相同的查询,第二次就是从本地缓存中得到上一次的查询结果

Mybatis是默认开启一级缓存的,无法关闭。比如在一个会话中连续两次执行同一个方法, 得到的是同一个对象

一级缓存在一下六种情况会失效:
           1.不同的会话
           2.同一个会话,两次相同查询中间有增删改操作,因为都会调用clearLocalCache()方法清除缓存
           3.同一个会话,查询(条件)参数不同
           4.同一个会话,调用清楚会话内容操作 SqlSession.flushCache()
           5.同一个会话,SQL相同与条件(参数)相同,但是方法名不同
           6.同一个会话,分页信息(偏移量和需要返回的记录数)不同

举例:

	public void testCache1() {
		
		SqlSession session = getSqlSession();
		CustMapper mapper = session.getMapper(CustMapper.class);
		//SQL:select cust_id,cust_name from cust where cust_id=#{custId};
		Cust cust1 = mapper.getCustById(1);
		//SQL:select cust_id,cust_name from cust where cust_id=#{custId};
		//虽然getCustById和getCustByIdNew使用的相同条件和相同SQL,但方法不同不能使用缓存
		Cust cust2 = mapper.getCustByIdNew(1);

		//如果在这里执行一个增删改操作,那么本地缓存中的 数据将会被清空,下面的getCustByIdNew(1)会再次从数据库中查询数据
		//mapper.addCust(new Cust("TonTan"))
		
		//因为和Cust cust2 = mapper.getCustByIdNew(1);方法名(全类名+方法名)、条件、SQL、默认分页信息都一样所以可以使用缓存
		Cust cust3 = mapper.getCustByIdNew(1);
		
	}

 

附上一些源码分析:

一级缓存是使用了名为PerpetualCache的类,变量名为localCache,其内部就是一个Map<Object,Object>。

public class PerpetualCache implements Cache {

  private final String id;

  private Map<Object, Object> cache = new HashMap<Object, Object>();

}

Mybatis每次执行查询的时候会执行localCache.get(key),这个Key是CacheKey类,他的hashCode值是由如下几个因素决定,只要这几个因素完全一致就可以从localCache中找到之前的查询结果。生成key的方法如下:

  public CacheKey createCacheKey(MappedStatement ms, Object parameterObject, RowBounds rowBounds, BoundSql boundSql) {
    if (closed) {
      throw new ExecutorException("Executor was closed.");
    }
    CacheKey cacheKey = new CacheKey();
    cacheKey.update(ms.getId());
    cacheKey.update(rowBounds.getOffset());
    cacheKey.update(rowBounds.getLimit());
    cacheKey.update(boundSql.getSql());
    //其他部分没有复制出来
}

ms.getId是方法的全类名+方法名
rowBounds.getOffset()分页查询时的偏移量
rowBounds.getLimit()分页查询时的查询记录数
boundSql.getSql()sql本身

什么时候将查询结果放入缓存的喃?

  private <E> List<E> queryFromDatabase(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
    List<E> 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;
  }

localCache.putObject(key, list);就是它了。。。。。。。

那为什么调用了增删改缓存就失效了喃,因为他们都底层都是调用update方法,而它调用了clearLocalCache(),所以。。你懂的。

 

最后提一个全局配置参数:localCacheScope,它可以设置为SESSION或者STATEMENT,默认为SESSION,但是这样的话,可能取到脏数据,假如设置为STATEMENT的话就可以避免这种情况,相当于禁止了一级缓存。

转载于:https://my.oschina.net/u/3049601/blog/1615703

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值