Mybatis-一级缓存

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

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

一级缓存在一下六种状况会失效:
           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);
		
	}

 

附上一些源码分析:session

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

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自己code

何时将查询结果放入缓存的喃?对象

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);就是它了。。。。。。。rem

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

 

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

相关文章
相关标签/搜索