Mybatis缓存模块
Mybatis缓存模块缓存模块要实现哪些功能Mybatis缓存的实现是基于Map的,从缓存里面读写数据是缓存模块的核心基础功能;除核心功能之外,有很多额外的附加功能,如:防止缓存击穿,添加缓存清空策略(fifo、lru)、序列化功能、日志能力、定时清空能力等;附加功能可以以任意的组合附加到核心基础功能之上;
这个模块因为有很多附加功能,而且这些功能是自由组合的所以Mybatis采用了装饰者模式。装饰者模式不太了解的可以看我之前的文章
https:mp。toutiao。comprofilev4graphicpreview?pgcid7009090446181990949
注意这里看的都是一级缓存
这里查看几个主要的类:Cache:对应装饰者的抽象组件CacheKey:实体类作为缓存的keyPerpetualCache:具体组件BlockingCache:具体装饰器
CachepublicinterfaceCache{缓存实现类的idStringgetId();往缓存中添加数据,这里的key是Object,key一般是CacheKey对象voidputObject(Objectkey,Objectvalue);根据指定的key从缓存获取数据ObjectgetObject(Objectkey);ObjectremoveObject(Objectkey);voidclear();intgetSize();defaultReadWriteLockgetReadWriteLock(){returnnull;}}
PerpetualCache:这个类提供了基本的缓存功能PerpetualCacheimplementsCache缓存的mapprivatefinalMapObject,ObjectcachenewHashMap();OverridepublicvoidputObject(Objectkey,Objectvalue){cache。put(key,value);}
BlockingCachepublicclassBlockingCacheimplementsCache{阻塞的超时时间privatelongtimeout;被装饰的对象,一般是PerpetualCache(组件实现类)privatefinalCachedelegate;锁对象集合,这里的颗粒度是keyprivatefinalConcurrentHashMapObject,CountDownLatchlocks;放缓存信息这个行为不需要加锁OverridepublicvoidputObject(Objectkey,Objectvalue){try{delegate。putObject(key,value);}finally{releaseLock(key);}}获取对象OverridepublicObjectgetObject(Objectkey){获取锁acquireLock(key);Objectvaluedelegate。getObject(key);if(value!null){数据获取成功后释放锁:从lock集合中移除releaseLock(key);}returnvalue;}这个方法在3。5版本的时候是基于ReentrantLock来处理的本次看的版本为3。8paramkeyprivatevoidacquireLock(Objectkey){这里使用CountDownLatch多线程工具保证一个时间内只有一个线程在访问CountDownLatchnewLatchnewCountDownLatch(1);while(true){locks是cuncurrentHashMap线程安全的容器,调用putIfAbsent,利用了容器特性,如果设置过则不会设置成功则会进入上面的自旋CountDownLatchlatchlocks。putIfAbsent(key,newLatch);if(latchnull){break;}try{判断是否有超时时间if(timeout0){booleanacquiredlatch。await(timeout,TimeUnit。MILLISECONDS);if(!acquired){thrownewCacheException(Couldntgetalockintimeoutforthekeykeyatthecachedelegate。getId());}}else{latch。await();}}catch(InterruptedExceptione){thrownewCacheException(Gotinterruptedwhiletryingtoacquirelockforkeykey,e);}}}privatevoidreleaseLock(Objectkey){CountDownLatchlatchlocks。remove(key);if(latchnull){thrownewIllegalStateException(Detectedanattemptatreleasingunacquiredlock。Thisshouldneverhappen。);}这里释countDown释放了锁latch。countDown();}}
思考一下为什么获取缓存要加锁的方式?
其实这个是为了防止缓存穿透的。当大量请求来获取缓存中没有对应数据的时候可能发生缓存击穿。这种时候加上锁就可以防止这种问题的产生。
CacheKey:这个类重点是看一下重写的hash和equal方法publicclassCacheKeyimplementsCloneable,Serializable{privatestaticfinallongserialVersionUID1146682552656046210L;publicstaticfinalCacheKeyNULLCACHEKEYnewCacheKey(){Overridepublicvoidupdate(Objectobject){thrownewCacheException(Notallowedtoupdateanullcachekeyinstance。);}OverridepublicvoidupdateAll(Object〔〕objects){thrownewCacheException(Notallowedtoupdateanullcachekeyinstance。);}};privatestaticfinalintDEFAULTMULTIPLIER37;privatestaticfinalintDEFAULTHASHCODE17;参与hash计算的乘数privatefinalintmultiplier;CacheKey的hash值,在update函数中实时运算出来的privateinthashcode;校验和,hash值的和privatelongchecksum;updateList的中元素个数privateintcount;8212017Sonarlintflagsthisasneedingtobemarkedtransient。Whiletrueifcontentisnotserializable,thisisnotalwaystrueandthusshouldnotbemarkedtransient。privateListObjectupdateList;publicCacheKey(){this。hashcodeDEFAULTHASHCODE;this。multiplierDEFAULTMULTIPLIER;this。count0;this。updateListnewArrayList();}publicCacheKey(Object〔〕objects){this();updateAll(objects);}publicintgetUpdateCount(){returnupdateList。size();}publicvoidupdate(Objectobject){object的基本hash值intbaseHashCodeobjectnull?1:ArrayUtil。hashCode(object);更新count和checksumcount;checksumbaseHashCode;baseHashCodecount;hashcodemultiplierhashcodebaseHashCode;将对象添加到updateList中updateList。add(object);}publicvoidupdateAll(Object〔〕objects){for(Objecto:objects){update(o);}}重写的eq方法paramobjectreturnOverridepublicbooleanequals(Objectobject){比较是不是同一个对象if(thisobject){returntrue;}是否类型相同if(!(objectinstanceofCacheKey)){returnfalse;}finalCacheKeycacheKey(CacheKey)object;hashcode是否相同if(hashcode!cacheKey。hashcode){returnfalse;}checksum是否相同if(checksum!cacheKey。checksum){returnfalse;}count是否相同if(count!cacheKey。count){returnfalse;}以上都不相同,才按顺序比较updateList中元素的hash值是否一致for(inti0;iupdateList。size();i){ObjectthisObjectupdateList。get(i);ObjectthatObjectcacheKey。updateList。get(i);if(!ArrayUtil。equals(thisObject,thatObject)){returnfalse;}}returntrue;}OverridepublicinthashCode(){returnhashcode;}OverridepublicStringtoString(){StringJoinerreturnValuenewStringJoiner(:);returnValue。add(String。valueOf(hashcode));returnValue。add(String。valueOf(checksum));updateList。stream()。map(ArrayUtil::toString)。forEach(returnValue::add);returnreturnValue。toString();}OverridepublicCacheKeyclone()throwsCloneNotSupportedException{CacheKeyclonedCacheKey(CacheKey)super。clone();clonedCacheKey。updateListnewArrayList(updateList);returnclonedCacheKey;}}
封面侵权删