先來(lái)看一個(gè)例子囱怕,我們先發(fā)起請(qǐng)求/testA紧武,隨后立即發(fā)起請(qǐng)求/testB:
@Transactional
@PostMapping("/testA")
public void testA() throws InterruptedException {
// 請(qǐng)求a 第一次查詢 原值為100
SellerCreditDO testDO = testMapper.findById(TEST_ID);
System.out.println("request a ==> before change : " + testDO.getCreditScore());
// sleep期間發(fā)起請(qǐng)求b
Thread.sleep(5000L);
// 請(qǐng)求a 第二次查詢
testDO = testMapper.findById(TEST_ID);
System.out.println("request a ==> after change : " + testDO.getCreditScore());
}
@PostMapping("/testB")
public void testB() {
// 請(qǐng)求a第一次查詢執(zhí)行后發(fā)起請(qǐng)求b更新對(duì)應(yīng)值值為90
SellerCreditDO testDO = testMapper.findById(TEST_ID);
testDO.setCreditScore(90);
testMapper.update(testDO);
System.out.println("request b => change value to 90 -----");
}
由于spring默認(rèn)使用數(shù)據(jù)庫(kù)的隔離級(jí)別吠裆,而阿里云rds默認(rèn)使用的隔離級(jí)別為read committed按厘,因此這里使用的是rc隔離級(jí)別抵恋,根據(jù)我們對(duì)隔離級(jí)別的認(rèn)識(shí)纲菌,這里的輸出應(yīng)該為:
request a ==> before change : 100
request b => change value to 90 -----
request a ==> after change : 90
但是實(shí)際上挠日,這里的輸出為:
request a ==> before change : 100
request b => change value to 90 -----
request a ==> after change : 100
這里是否是因?yàn)閟pring使用的隔離級(jí)別不是read committed?我們來(lái)嘗試做幾個(gè)修改:
- 我們將mybatis一級(jí)緩存的scope設(shè)置為statement(mybatis一級(jí)緩存默認(rèn)開啟翰舌,為session級(jí)別嚣潜。):
configuration.setLocalCacheScope(LocalCacheScope.STATEMENT);
再次測(cè)試,我們發(fā)現(xiàn)得到了預(yù)期的輸出:
request a ==> before change : 100
request b => change value to 90 -----
request a ==> after change : 90
- 不修改mybatis一級(jí)緩存的scope椅贱,去掉testA方法上的@Transaction注解
再次測(cè)試懂算,發(fā)現(xiàn)也能得到預(yù)期的輸出。
有了上面的案例庇麦,經(jīng)過分析框架代碼可以總結(jié)如下:
- mybatis一級(jí)緩存默認(rèn)開啟计技,是sqlSession級(jí)別的緩存,在同一個(gè)sqlSession下山橄,對(duì)相同條件的sql查詢結(jié)果會(huì)進(jìn)行緩存垮媒。
- sqlSession調(diào)用flush或者close之后,會(huì)清理mybatis一級(jí)緩存航棱;
session內(nèi)發(fā)生 insert睡雇、update 和 delete 操作時(shí),會(huì)清空緩存饮醇;
一個(gè)session內(nèi)發(fā)生的insert它抱、update 和 delete 操作,不會(huì)影響其他session內(nèi)的一級(jí)緩存朴艰。 - 在spring集成mybatis時(shí)观蓄,如果不開啟事務(wù),spring對(duì)于每次查詢會(huì)使用不同的sqlSession呵晚,因此mybatis一級(jí)緩存是不生效的(每次查詢都是一個(gè)單獨(dú)的事務(wù));
如果開啟事務(wù)沫屡,spring在事務(wù)內(nèi)會(huì)使用同一個(gè)sqlSession進(jìn)行查詢饵隙,這個(gè)時(shí)候mybatis一級(jí)緩存是生效的,而這個(gè)時(shí)候沮脖,在某些場(chǎng)景下我們只根據(jù)隔離級(jí)別作出的判斷可能就不對(duì)了金矛,需要注意芯急。
建議:一般不要使用mybatis提供的緩存,將一級(jí)緩存設(shè)置為statement級(jí)別驶俊。