一級(jí)緩存首先做一個(gè)測(cè)試,,創(chuàng)建一個(gè)mapper配置文件和mapper接口,我這里用了最簡(jiǎn)單的查詢(xún)來(lái)演示,。
然后編寫(xiě)一個(gè)單元測(cè)試
運(yùn)行,,可以看到控制臺(tái)輸出(先配好log4j)為類(lèi)似如下圖日志 日志說(shuō)明了該操作執(zhí)行的sql語(yǔ)句已經(jīng)查詢(xún)的內(nèi)容,最后一行是我手動(dòng)通過(guò)System.out.printf輸出的結(jié)果,。 然后再加一條語(yǔ)句
之前的單元測(cè)試就變成了這個(gè)樣子 也就是在執(zhí)行完userMapper.findUsers();后立刻再執(zhí)行一遍userMapper.findUsers(); 可以想象,,其實(shí)這兩個(gè)操作執(zhí)行的sql是完全相同的,而且在這期間沒(méi)有對(duì)數(shù)據(jù)庫(kù)進(jìn)行過(guò)其他操作,。然后執(zhí)行該單元測(cè)試,,發(fā)現(xiàn)效果跟上面執(zhí)行一條的時(shí)候完全相同,也就是執(zhí)行第二次userMapper.findUsers();操作的時(shí)候沒(méi)有對(duì)數(shù)據(jù)庫(kù)進(jìn)行查詢(xún),,那么得到的數(shù)據(jù)是從哪里來(lái)的,?答案是一級(jí)緩存。 mybatis一級(jí)緩存是指在內(nèi)存中開(kāi)辟一塊區(qū)域,,用來(lái)保存用戶(hù)對(duì)數(shù)據(jù)庫(kù)的操作信息(sql)和數(shù)據(jù)庫(kù)返回的數(shù)據(jù),,如果下一次用戶(hù)再執(zhí)行相同的請(qǐng)求,那么直接從內(nèi)存中讀數(shù)數(shù)據(jù)而不是從數(shù)據(jù)庫(kù)讀取。
對(duì)sqlsession執(zhí)行commit操作,,也就意味著用戶(hù)執(zhí)行了update、delete等操作,,那么數(shù)據(jù)庫(kù)中的數(shù)據(jù)勢(shì)必會(huì)發(fā)生變化,,如果用戶(hù)請(qǐng)求數(shù)據(jù)仍然使用之前內(nèi)存中的數(shù)據(jù),那么將讀到臟數(shù)據(jù),。所以在執(zhí)行sqlsession操作后,,會(huì)清除保存數(shù)據(jù)的HashMap,用戶(hù)在發(fā)起查詢(xún)請(qǐng)求時(shí)就會(huì)重新讀取數(shù)據(jù)并放入一級(jí)緩存中了,。 上述測(cè)試就是在第一查詢(xún)完后執(zhí)行了commit操作,,再進(jìn)行查詢(xún)。與之前的測(cè)試不同的是,,這次測(cè)試控制臺(tái)打印了兩組查詢(xún)結(jié)果,,說(shuō)明在commit之后mybatis對(duì)數(shù)據(jù)重新進(jìn)行了查詢(xún)。
一般在mybatis集成spring時(shí),,會(huì)把SqlSessionFactory設(shè)置為單例注入到IOC容器中,,不把sqlsession也設(shè)置為單例的原因是sqlsession是線(xiàn)程不安全的,所以不能為單例,。那也就意味著其實(shí)是有關(guān)閉sqlsession的過(guò)程的,。其實(shí),對(duì)于每一個(gè)service中的sqlsession是不同的,,這是通過(guò)mybatis-spring中的org.mybatis.spring.mapper.MapperScannerConfigurer創(chuàng)建sqlsession自動(dòng)注入到service中的,。 二級(jí)緩存在使用二級(jí)緩存之前,先測(cè)試之前提到過(guò)的關(guān)閉sqlsession后會(huì)清空緩存的問(wèn)題,,把junit代碼修改一下
這段代碼在第一次查詢(xún)完后關(guān)閉sqlsession,,然后創(chuàng)建新的sqlsession和mapper來(lái)重新執(zhí)行一次查詢(xún)操作,可以預(yù)見(jiàn),,執(zhí)行結(jié)果如圖 說(shuō)明關(guān)閉了sqlsession后的確把之前的緩存數(shù)據(jù)清空了,,之后再執(zhí)行同樣的查詢(xún)操作也會(huì)再訪(fǎng)問(wèn)一遍數(shù)據(jù)庫(kù)。為了解決這個(gè)問(wèn)題,,需要使用二級(jí)緩存 一級(jí)緩存的作用域僅限于一個(gè)sqlsession,,但是二級(jí)緩存的作用域是一個(gè)namespace。但并不是意味著同一個(gè)namespace創(chuàng)建的mapper可以互相讀取緩存內(nèi)容,這里的原則是,,如果開(kāi)啟了二級(jí)緩存,,那么在關(guān)閉sqlsession后,會(huì)把該sqlsession一級(jí)緩存中的數(shù)據(jù)添加到namespace的二級(jí)緩存中,。 接下測(cè)試,,先需要開(kāi)啟二級(jí)緩存。 1.打開(kāi)二級(jí)緩存總開(kāi)關(guān)
2.打開(kāi)需要使用二級(jí)緩存的mapper的開(kāi)關(guān) 在需要開(kāi)啟二級(jí)緩存的mapper.xml中加入caceh標(biāo)簽
3.POJO序列化 讓需要使用二級(jí)緩存的POJO類(lèi)實(shí)現(xiàn)Serializable接口,,如
通過(guò)之前三步操作就可以使用二級(jí)緩存了,接下來(lái)測(cè)試,。添加一個(gè)Junit方法
執(zhí)行后可以發(fā)現(xiàn),,控制臺(tái)值輸出了一次查詢(xún)過(guò)程,也可以證明二級(jí)緩存開(kāi)啟成功,。 還有一個(gè)問(wèn)題,,之前說(shuō)了,即使開(kāi)啟了二級(jí)緩存,,不同的sqlsession之間的緩存數(shù)據(jù)也不是想互訪(fǎng)就能互訪(fǎng)的,,必須等到sqlsession關(guān)閉了以后,才會(huì)把其一級(jí)緩存中的數(shù)據(jù)寫(xiě)入二級(jí)緩存,。為了測(cè)試這個(gè),,把上述代碼中的
注釋?zhuān)敲粗暗拇a就變成了 再執(zhí)行,發(fā)現(xiàn)控制太又輸出了兩次的查詢(xún)過(guò)程,,所以可以印證,,只有關(guān)閉了sqlsession之后,才會(huì)把其中一級(jí)緩存數(shù)據(jù)寫(xiě)入二級(jí)緩存,。 緩存配置
在默認(rèn)情況下,,當(dāng)sqlsession執(zhí)行commit后會(huì)刷新緩存,但是也可以強(qiáng)制設(shè)置為不刷新,,在不需要刷新的標(biāo)簽中加入
如
那么,,無(wú)論是否執(zhí)行commit,緩存都不會(huì)刷新了,。但是這樣會(huì)造成臟讀,,只有在特殊情況下才使用
有些情況下,需要設(shè)置自動(dòng)刷新緩存,,那么需要配置對(duì)應(yīng)mapper中的cache標(biāo)簽,。
該屬性表示每隔10秒鐘自動(dòng)刷新一遍緩存 |
|
來(lái)自: 觀(guān)審美2 > 《Java框架》