上一章節咱們簡單瞭解了二級緩存的配置。今天咱們詳細分析下二級緩存以及爲何不建議使用二級緩存。算法
一級緩存針對的是sqlsession。二級緩存針對的是namespace層面的。sql
public Executor newExecutor(Transaction transaction, ExecutorType executorType) { executorType = executorType == null ? defaultExecutorType : executorType; executorType = executorType == null ? ExecutorType.SIMPLE : executorType; Executor executor; if (ExecutorType.BATCH == executorType) { executor = new BatchExecutor(this, transaction); } else if (ExecutorType.REUSE == executorType) { executor = new ReuseExecutor(this, transaction); } else { executor = new SimpleExecutor(this, transaction); } if (cacheEnabled) { executor = new CachingExecutor(executor); } executor = (Executor) interceptorChain.pluginAll(executor); return executor; }
cacheEnabled
這個屬性是控制二級緩存的配置的。而這個屬性在Configuration中默認是true。這裏說明了mybatis默認是開啓緩存功能的。二級緩存和一級緩存的區別其實除了範圍之外,他們的不一樣點就是順序不一樣。真正開啓二級緩存的是在mapper的xml中配置cache標籤就好了。SqlSession sqlSession = SqlSessionFactoryUtils.openSqlsession(); StudentMapper mapper = sqlSession.getMapper(StudentMapper.class); Student student = mapper.getStudentByIdAndName("1", "1"); System.out.println(student); SqlSession sqlSession1 = SqlSessionFactoryUtils.sqlSessionFactory.openSession(); StudentMapper mapper1 = sqlSession1.getMapper(StudentMapper.class); Student studentByIdAndName = mapper1.getStudentByIdAndName("1", "1"); System.out.println(studentByIdAndName);
@Data @Builder @Accessors(chain = true) public class Student { /** * 學生索引id */ private String id; /** * 姓名 */ private String userName; /** * 用戶暱稱 */ private String userNick; /** * 年齡 */ private Integer age; /** * 性別 true : 男 ; false : 女 */ private SexEnum sex; /** * 生日 */ private Date birth; /** * 身高 */ private Double height; }
CacheingExecutor.commit()
這個方法裏面有事物的提交tcm.commit()
。
因此他的裝飾鏈爲:SynchronizedCache->LogginCache->SerializedCache->LruCache->PerPetualCache設計模式
而在上面的tcm.commit就是在SerializedCache進行緩存對象的。因此咱們以前的代碼是sqlsession沒有提交。因此代碼只要稍微改動下。緩存
SqlSession sqlSession = SqlSessionFactoryUtils.openSqlsession(); StudentMapper mapper = sqlSession.getMapper(StudentMapper.class); Student student = mapper.getStudentByIdAndName("1", "1"); System.out.println(student); sqlSession.commit(); SqlSession sqlSession1 = SqlSessionFactoryUtils.sqlSessionFactory.openSession(); StudentMapper mapper1 = sqlSession1.getMapper(StudentMapper.class); Student studentByIdAndName = mapper1.getStudentByIdAndName("1", "1"); System.out.println(studentByIdAndName);
SynchronizedCache : 同步Cache.這個類就是保證線程安全。因此他的方法基本上是加上synchronized
來保證線程安全的。安全
LoggingCache : 日誌。在上面咱們有個日誌是Cache Hit Ratio 0.5 表示二級緩存的命中率。session
SerializedCache : 就是用來序列化數據的。mybatis
LruCache : 回收cache的算法app
PerPetualCache :基本Cache .ide
@Override public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException { //獲取Cache對象 Cache cache = ms.getCache(); if (cache != null) { //根據statment配置刷新緩存,默認是insert、update、delete會刷新緩存 flushCacheIfRequired(ms); //二級緩存開啓入口。 if (ms.isUseCache() && resultHandler == null) { //這個方法主要用來處理存儲過程。後續章節說明 ensureNoOutParams(ms, boundSql); @SuppressWarnings("unchecked") //經過緩存事物查詢數據 List<E> list = (List<E>) tcm.getObject(cache, key); if (list == null) { //調用委託類查詢數據 list = delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql); //加入緩存,供下次獲取 tcm.putObject(cache, key, list); } return list; } } //沒有開啓二級緩存則繼續往下走 return delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql); }
PerpetualCache
是緩存鏈上最基本的緩存類。咱們自定義的緩存就是替代這個類的。在mybatis中會現根據咱們註冊進來的類進行實例化。若是沒有則用默認的PerpetualCache
這個類做爲基礎緩存類。