一級緩存
主要內容: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