為什么不推薦使用 MyBatis 二級(jí)緩存?
閱讀本文大概需要 6?分鐘。
來(lái)自:blog.csdn.net/xujingyiss/article/details/123481116
一級(jí)緩存
應(yīng)用場(chǎng)景
member_id字段查詢出會(huì)員表,最后進(jìn)行數(shù)據(jù)整合。而如果訂單表中存在重復(fù)的member_id,就會(huì)出現(xiàn)很多重復(fù)查詢。生效的條件
必須是相同的會(huì)話 必須是同一個(gè) mapper,即同一個(gè) namespace 必須是相同的 statement,即同一個(gè) mapper 中的同一個(gè)方法 必須是相同的 sql 和參數(shù) 查詢語(yǔ)句中間沒(méi)有執(zhí)行? session.clearCache()?方法查詢語(yǔ)句中間沒(méi)有執(zhí)行 insert/update/delete 方法(無(wú)論變動(dòng)記錄是否與緩存數(shù)據(jù)有無(wú)關(guān)系)
與springboot集成時(shí)一級(jí)緩存不生效原因

SqlSessionUtils?的?getSqlSession?方法,在這個(gè)方法中會(huì)嘗試在事務(wù)管理器中獲取 SqlSession,如果沒(méi)有開(kāi)啟事務(wù),那么就會(huì) new 一個(gè)?DefaultSqlSession。
解決與springboot集成時(shí)一級(jí)緩存不生效問(wèn)題
SqlSession,取不到才會(huì)去創(chuàng)建新的?SqlSession。所以可以猜測(cè)只要將方法開(kāi)啟事務(wù),那么一級(jí)緩存就會(huì)生效。@Transactional?注解,看下效果:

SqlSessionUtils?中,在獲取到?SqlSession?后,會(huì)調(diào)用?registerSessionHolder方法注冊(cè)?SessionHolder?到事務(wù)管理器:
TransactionSynchronizationManager?的?bindResource?方法中操作的,將?SessionHolder?保存到線程本地變量(ThreadLocal) resources?中,這是每個(gè)線程獨(dú)享的。
BaseExecutor?中的?queryFromDatabase?方法中。執(zhí)行 doQuery 從數(shù)據(jù)庫(kù)中查詢數(shù)據(jù)后,會(huì)立馬緩存到?localCache(PerpetualCache類型)?中:
二級(jí)緩存
應(yīng)用場(chǎng)景
@RestController
@RequestMapping("item")
public?class?ItemController?{
?
????@Autowired
????private?ItemMapper?itemMapper;
?
????@GetMapping("/{id}")
????public?void?getById(@PathVariable("id")?Long?id)?{
????????System.out.println("====================?begin?====================");
????????Item?item?=?itemMapper.selectById(id);
????????System.out.println(JSON.toJSONString(item));
????}
?
}?

開(kāi)啟的方法
cache-enabled?為 truemybatis-plus:
??configuration:
????cache-enabled:?true
@CacheNamespace?注解
Serializable?接口
生效的條件
當(dāng)會(huì)話提交或關(guān)閉之后才會(huì)填充二級(jí)緩存 必須是同一個(gè) mapper,即同一個(gè)命名空間 必須是相同的 statement,即同一個(gè) mapper 中的同一個(gè)方法 必須是相同的 SQL 語(yǔ)句和參數(shù) 如果? readWrite=true(默認(rèn)就是true),實(shí)體對(duì)像必須實(shí)現(xiàn)?Serializable?接口
緩存清除條件
只有修改會(huì)話提交之后,才會(huì)執(zhí)行清空操作 xml 中配置的 update 不能清空? @CacheNamespace?中的緩存數(shù)據(jù)任何一種增刪改操作都會(huì)清空整個(gè)? namespace?中的緩存
源碼中是如何填充二級(jí)緩存的?

TransactionalCache?的?flushPendingEntries?方法中填充二級(jí)緩存:
查詢時(shí)如何使用二級(jí)緩存?
MybatisCachingExecutor?的 query 方法,里面會(huì)從?TransactionalCacheManager?中嘗試根據(jù) key 獲取二級(jí)緩存的內(nèi)容。
PerpetualCache?中獲取緩存的:
LoggingCache?中:
為什么mybatis默認(rèn)不開(kāi)啟二級(jí)緩存?
namespace(mapper)?為單位的,不同 namespace 下的操作互不影響。且 insert/update/delete 操作會(huì)清空所在?namespace?下的全部緩存。ItemMapper?以及?XxxMapper,在?XxxMapper?中做了表關(guān)聯(lián)查詢,且做了二級(jí)緩存。此時(shí)在?ItemMapper?中將 item 信息給刪了,由于不同 namespace 下的操作互不影響,XxxMapper?的二級(jí)緩存不會(huì)變,那之后再次通過(guò)?XxxMapper?查詢的數(shù)據(jù)就不對(duì)了,非常危險(xiǎn)。@Mapper
@Repository
@CacheNamespace
public?interface?XxxMapper?{
?
????@Select("select?i.id?itemId,i.name?itemName,p.amount,p.unit_price?unitPrice?"?+
????????????"from?item?i?JOIN?payment?p?on?i.id?=?p.item_id?where?i.id?=?#{id}")
????List?getPaymentVO(Long?id) ;
?
}
?
?
@Autowired
private?XxxMapper?xxxMapper;
?
@Test
void?test()?{
?System.out.println("====================?查詢PaymentVO?====================");
?List?voList?=?xxxMapper.getPaymentVO(1L);
?System.out.println(JSON.toJSONString(voList.get(0)));
?System.out.println("====================??更新item表的name?====================?");
?Item?item?=?itemMapper.selectById(1);
?item.setName("java并發(fā)編程");
?itemMapper.updateById(item);
?System.out.println("====================??重新查詢PaymentVO?====================?");
?List?voList2?=?xxxMapper.getPaymentVO(1L);
?System.out.println(JSON.toJSONString(voList2.get(0)));
}
test()方法中前后兩次調(diào)用了?xxxMapper.getPaymentVO?方法,因?yàn)闆](méi)有加?@Transactional?注解,所以前后兩次查詢,是兩個(gè)不同的會(huì)話,第一次查詢完后,SqlSession?會(huì)自動(dòng) commit,所以二級(jí)緩存能夠生效;itemMapper?與?xxxMapper?不是同一個(gè)命名空間,所以?itemMapper?執(zhí)行的更新操作不會(huì)影響到?xxxMapper?的二級(jí)緩存;xxxMapper.getPaymentVO,發(fā)現(xiàn)取出的值是走緩存的,itemName?還是老的。但實(shí)際上?itemName?在上面已經(jīng)被改了!
推薦閱讀:
面試官:一千萬(wàn)的數(shù)據(jù),你是怎么查詢的?
互聯(lián)網(wǎng)初中高級(jí)大廠面試題(9個(gè)G) 內(nèi)容包含Java基礎(chǔ)、JavaWeb、MySQL性能優(yōu)化、JVM、鎖、百萬(wàn)并發(fā)、消息隊(duì)列、高性能緩存、反射、Spring全家桶原理、微服務(wù)、Zookeeper......等技術(shù)棧!
?戳閱讀原文領(lǐng)??!? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??朕已閱?

