一级缓存
主要内容:sql
一级缓存也叫本地缓存(LocalCache),Mybatis的一级缓存是会话级别(SqlSession)层面进行缓存的。Mybatis的一级缓存是默认开启的。咱们开发项目中不须要作任何配置,可是若是想关闭一级缓存,可使用localCacheScopde=statement来关闭。数据库
如何关闭一级缓存呢?
在BaseExecutor的中,请看下面代码:缓存
为何说是SqlSession层面缓存?
就是一级缓存的生命周期和一个SqlSession对象的生命周期同样。mybatis
下面这段中,就会使用到一级缓存。app
SqlSession sqlSession1 = sqlSessionFactory.openSession(); User user1 = sqlSession1.selectOne("com.tian.mybatis.mapper.UserMapper.selectUserById", 1); User user2 = sqlSession1.selectOne("com.tian.mybatis.mapper.UserMapper.selectUserById", 1);
结果输出:ide
用两张图来总结:ui
第一次:查数据库,放入到缓存中。this
第二次:直接从缓存中获取。spa
下面这段代码中就使用不到缓存3d
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); sqlSession = sqlSessionFactory.openSession(); sqlSession1 = sqlSessionFactory.openSession(); UserMapper userMapper = sqlSession.getMapper(UserMapper.class); UserMapper userMapper1 = sqlSession1.getMapper(UserMapper.class); System.out.println("第一次查询"); System.out.println(userMapper.selectById(1)); User user = new User(); user.setUserName("tian111"); user.setId(1); userMapper1.updateAuthorIfNecessary(user); System.out.println("第二次查询"); System.out.println(userMapper.selectById(1));
输出结果:
用三张图来总结:
第一次查询:sqlSession1查询数据库,放入到缓存中。
更新:sqlSession2进行更新,注意这里写入的是sqlSession本身的本地缓存。
第二次查询:sqlSession1第二次查询。
记住是一级缓存只能是同一个SqlSession对象就好了。
一级缓存维护在哪里的?
既然一级缓存的生命周期和SqlSession一致,那么咱们能够猜测,这个缓存是否是就维护在SqlSession中呢?
SqlSession的默认实现类DefaultSqlSession,在DefaultSqlSession中只有两个属性可能存放缓存:
private final Configuration configuration; private final Executor executor;
configuration是全局的,确定不会放缓存。
那就只能把但愿寄托于Executor了。因为Executor是个接口,咱们能够看看他的实现类:
另外这里有个BaseExecutor。有各种也得瞄瞄。一看竟然有东西。
public abstract class BaseExecutor implements Executor { private static final Log log = LogFactory.getLog(BaseExecutor.class); protected Transaction transaction; protected Executor wrapper; protected ConcurrentLinkedQueue<DeferredLoad> deferredLoads; //熟悉的家伙,基本缓存 protected PerpetualCache localCache; protected PerpetualCache localOutputParameterCache; protected Configuration configuration; protected int queryStack; private boolean closed; 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; } }
再看看BaseExecutor类图:
因此这就证实了,这个缓存是维护在SqlSession里。
一级缓存何时被清空?
在执行update、insert、delete、flushCache="true"、commit、rollback、LocalCacheScope.STATEMENT等状况下,一级缓存就都会被清空。
@Override public void clearLocalCache() { if (!closed) { localCache.clear(); localOutputParameterCache.clear(); } }
update时,一级缓存会被清空。delete和insert都是调用这个update。能够从SqlSession的insert、update、delete方法跟踪。
LocalCacheScope.STATEMENT时,一级缓存会被清空。在BaseExecutor里的query方法中:
事务提交回滚时,一级缓存会被清空。
flushCache="true"时,一级缓存会被清空。
一级缓存key是什么?
下面就是一级缓存key的建立过程
@Override 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()); List<ParameterMapping> parameterMappings = boundSql.getParameterMappings(); TypeHandlerRegistry typeHandlerRegistry = ms.getConfiguration().getTypeHandlerRegistry(); // mimic DefaultParameterHandler logic for (ParameterMapping parameterMapping : parameterMappings) { if (parameterMapping.getMode() != ParameterMode.OUT) { Object value; String propertyName = parameterMapping.getProperty(); if (boundSql.hasAdditionalParameter(propertyName)) { value = boundSql.getAdditionalParameter(propertyName); } else if (parameterObject == null) { value = null; } else if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) { value = parameterObject; } else { MetaObject metaObject = configuration.newMetaObject(parameterObject); value = metaObject.getValue(propertyName); } cacheKey.update(value); } } if (configuration.getEnvironment() != null) { // issue #176 cacheKey.update(configuration.getEnvironment().getId()); } return cacheKey; }
id:com.tian.mybatis.mapper.UserMapper.selectById
key的生成策略:id + offset + limit + sql + param value + environment id,这些值都相同,生成的key就相同。
示例:
一级缓存总结
一级缓存的生命周期和SqlSession对象的生命周期一致。因此缓存维护在SqlSession中的属性executor里。
一级缓存默认开启。能够经过修改配置项把一级缓存关掉。
清空一级缓存的方式有:
- update、insert、delete
- flushCache="true"
- commit、rollback
- LocalCacheScope.STATEMENT