您好,登錄后才能下訂單哦!
這篇文章主要為大家展示了“MyBatis中的一級(jí)和二級(jí)緩存怎么用”,內(nèi)容簡而易懂,條理清晰,希望能夠幫助大家解決疑惑,下面讓小編帶領(lǐng)大家一起研究并學(xué)習(xí)一下“MyBatis中的一級(jí)和二級(jí)緩存怎么用”這篇文章吧。
緩存是存在內(nèi)存中的臨時(shí)數(shù)據(jù),通過將我們 「經(jīng)常查詢但不常變的數(shù)據(jù)」 放在內(nèi)存中,當(dāng)我們查詢數(shù)據(jù)時(shí)就不在需要從磁盤讀取,而只需要從緩存中查詢即可,大大提升了查詢的效率,解決了高并發(fā)系統(tǒng)的性能問題。
既然我們可以直接從數(shù)據(jù)庫中查詢數(shù)據(jù),那為什么還要需要緩存呢?通過使用緩存,我們能夠減少和數(shù)據(jù)庫之間的交互頻率,減少系統(tǒng)開銷,從而提高系統(tǒng)的效率。
MyBatis 內(nèi)置了一個(gè)強(qiáng)大的事務(wù)性查詢緩存機(jī)制,通過它能夠十分方便的配置和定制。默認(rèn)情況下,MyBatis 默認(rèn)定義了兩級(jí)緩存,而且為了提高擴(kuò)展性,定義了緩存接口 Cache
,我們能十分方便的實(shí)現(xiàn) Cache
接口來自定義二級(jí)緩存。
SqlSession
級(jí)別的緩存);namespace
級(jí)別的緩存,需要我們手動(dòng)進(jìn)行開啟和配置;也叫 「本地緩存」,在與數(shù)據(jù)庫同一次會(huì)話期間查詢到的數(shù)據(jù)放在本地緩存,當(dāng)要再次獲取相同數(shù)據(jù)時(shí),直接從緩存獲取即可,不用再次和數(shù)據(jù)庫交互。
每個(gè) SqlSession
中都有一個(gè) Executor
,每個(gè) Executor
中又有一個(gè) LocalCache
,當(dāng)我們進(jìn)行查詢操作時(shí),MyBatis 根據(jù)當(dāng)前執(zhí)行的語句生成 MapperdStatement
,然后在 Local Cache
中進(jìn)行查詢,如果存在(命中),直接返回給用戶。若緩存中不存在(未命中),則和數(shù)據(jù)庫交互查詢數(shù)據(jù),將結(jié)果寫入 Local Cache
,同時(shí)返回給用戶。
一級(jí)緩存即 SqlSession
級(jí)別的緩存,和我們之前的 CURD 操作差不多;
@Select("select * from user where id=#{id}")
User queryUserById(@Param("id") int id);
@Test
public void testQueryUserById() {
SqlSession sqlSession = MybatisUtil.getSqlSession();
UserDao mapper = sqlSession.getMapper(UserDao.class);
User user1 = mapper.queryUserById(1);
System.out.println(user1);
User user2 = mapper.queryUserById(1);
System.out.println(user2);
System.out.println(user1 == user2);
sqlSession.close();
}
通過結(jié)果可以看出,由于是在一次會(huì)話期間內(nèi)(SqlSession
級(jí)別),所以此時(shí)的 SQL 語句只查詢了一次,當(dāng)?shù)诙潍@取相同結(jié)果時(shí),直接從緩存中取結(jié)果即可,也就解釋了為什么 user1
和 user2
指向的是同一個(gè)對(duì)象;
一級(jí)緩存是默認(rèn)一直開啟的,我們是關(guān)閉不了的。但是有時(shí)候一級(jí)緩存會(huì)出現(xiàn)失效的情況,主要可能是如下幾種原因?qū)е拢?/p>
SqlSession
中緩存獨(dú)立」當(dāng)我們使用不同的 SqlSession
時(shí),有多少個(gè) SqlSession
就需要向數(shù)據(jù)庫發(fā)起多少次查詢請(qǐng)求。
@Test
public void testQueryUserById() {
SqlSession sqlSession1 = MybatisUtil.getSqlSession();
UserDao mapper1 = sqlSession1.getMapper(UserDao.class);
SqlSession sqlSession2 = MybatisUtil.getSqlSession();
UserDao mapper2 = sqlSession2.getMapper(UserDao.class);
User user1 = mapper1.queryUserById(1);
System.out.println(user1);
User user2 = mapper2.queryUserById(1);
System.out.println(user2);
System.out.println(user1 == user2);
sqlSession1.close();
sqlSession2.close();
}
當(dāng)位于同一個(gè) SqlSession
,但查詢條件不同時(shí),也會(huì)導(dǎo)致緩存失效;
@Test
public void testQueryUserById1() {
SqlSession sqlSession = MybatisUtil.getSqlSession();
UserDao mapper = sqlSession.getMapper(UserDao.class);
User user = mapper.queryUserById(1);
System.out.println(user);
User user2 = mapper.queryUserById(2);
System.out.println(user2);
System.out.println(user == user2);
sqlSession.close();
}
假如在同一 SqlSession
中,在兩次查詢之間進(jìn)行了其他的增刪改等操作,當(dāng)?shù)诙尾樵冞M(jìn)行時(shí),就會(huì)重新執(zhí)行 SQL 語句,導(dǎo)致緩存失效;
@Test
public void testQueryUserById() {
SqlSession sqlSession = MybatisUtil.getSqlSession();
UserDao mapper = sqlSession.getMapper(UserDao.class);
User user = mapper.queryUserById(1);
System.out.println(user);
mapper.updateUser(new User(2,"小玉","8349823"));
User user2 = mapper.queryUserById(1);
System.out.println(user2);
System.out.println(user == user2);
sqlSession.close();
}
當(dāng) SqlSession
相同時(shí),如果我們手動(dòng)清除了緩存,那么也會(huì)導(dǎo)致緩存失效的情況出現(xiàn)。
@Test
public void testQueryUserById1() {
SqlSession sqlSession = MybatisUtil.getSqlSession();
UserDao mapper = sqlSession.getMapper(UserDao.class);
User user = mapper.queryUserById(1);
System.out.println(user);
// 手動(dòng)清除緩存
sqlSession.clearCache();
User user2 = mapper.queryUserById(1);
System.out.println(user2);
System.out.println(user == user2);
sqlSession.close();
}
也叫 「全局緩存」,基于 namespace
的緩存,一個(gè) namespace
對(duì)應(yīng)一個(gè)二級(jí)緩存。
一級(jí)緩存的最大共享范圍是一個(gè) SqlSession
內(nèi)部,若多個(gè) SqlSession
之間要共享緩存,則需要用二級(jí)緩存。二級(jí)緩存一旦開啟,將會(huì)有多個(gè) CachingExecutor
來裝飾 Executor
,進(jìn)入一級(jí)緩存的查詢流程之前,先在 CachingExecutor
中進(jìn)行二級(jí)緩存的查詢,如上圖。此時(shí)數(shù)據(jù)的查詢流程是:
?二級(jí)緩存 -> 一級(jí)緩存 -> 數(shù)據(jù)庫
?
要使用二級(jí)緩存,通常需要有如下步驟:
mybatis-config.xml
)中開啟二級(jí)緩存;<setting name="cacheEnabled" value="true"/>
xxxMapper.xml
中配置二級(jí)緩存;<cache/>
配置之后,xxxMapper.xml
文件中的 select
語句將會(huì)被緩存,而 insert、update、delete
則會(huì)刷新緩存。此外還可以設(shè)置自定義屬性值來修改默認(rèn)屬性;
屬性 | 說明 |
---|---|
eviction | 清除策略 |
flushInterval | 刷新間隔,單位是 ms |
size | 引用數(shù)目,默認(rèn)為 1024 |
readOnly | 默認(rèn)為 false |
而清除策略也主要有如下 4 種:
清除策略 | 說明 |
---|---|
LRU | 「最近最少使用」:移除最長時(shí)間不被使用的對(duì)象 |
FIFO | 「先進(jìn)先出」:按對(duì)象進(jìn)入緩存的順序來移除 |
SOFT | 「軟引用」:基于垃圾回收器狀態(tài)和軟引用規(guī)則移除對(duì)象 |
WEAK | 「弱引用」:更積極地基于垃圾回收器狀態(tài)和若引用規(guī)則移除對(duì)象 |
@Test
public void testGetUserByPassword() {
SqlSession sqlSession = MybatisUtils.getSqlSession();
SqlSession sqlSession2 = MybatisUtils.getSqlSession();
UserDao mapper = sqlSession.getMapper(UserDao.class);
UserDao mapper2 = sqlSession.getMapper(UserDao.class);
User user = mapper.getUserByPassword("1234567");
System.out.println(user);
User user2 = mapper2.getUserByPassword("1234567");
System.out.println(user2);
System.out.println(user==user2);
sqlSession.close();
sqlSession2.close();
}
根據(jù)結(jié)果可以看出,此時(shí)的二級(jí)緩存已經(jīng)生效。若是未生效,則會(huì)和一級(jí)緩存中的結(jié)果一致,兩者指向不同的對(duì)象,但此時(shí)兩個(gè)引用指向同一對(duì)象,說明二級(jí)緩存成功。
以上是“MyBatis中的一級(jí)和二級(jí)緩存怎么用”這篇文章的所有內(nèi)容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內(nèi)容對(duì)大家有所幫助,如果還想學(xué)習(xí)更多知識(shí),歡迎關(guān)注億速云行業(yè)資訊頻道!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請(qǐng)聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。