Java Mybatis一級緩存和二級緩存
一、什么是緩存
緩存是內(nèi)存當(dāng)中一塊存儲數(shù)據(jù)的區(qū)域,目的是提高查詢效率。MyBatis會將查詢結(jié)果存儲在緩存當(dāng)中,當(dāng)下次執(zhí)行相同的SQL時不訪問數(shù)據(jù)庫,而是直接從緩存中獲取結(jié)果,從而減少服務(wù)器的壓力。
什么是緩存?
存在于內(nèi)存中的一塊數(shù)據(jù)。
緩存有什么作用?
減少程序和數(shù)據(jù)庫的交互,提高查詢效率,降低服務(wù)器和數(shù)據(jù)庫的壓力。
什么樣的數(shù)據(jù)使用緩存?
經(jīng)常查詢但不常改變的,改變后對結(jié)果影響不大的數(shù)據(jù)。
MyBatis緩存分為哪幾類?
一級緩存和二級緩存
如何判斷兩次Sql是相同的?
查詢的Sql語句相同 傳遞的參數(shù)值相同 對結(jié)果集的要求相同 預(yù)編譯的模板Id相同
二、Mabtis一級緩存
MyBatis一級緩存也叫本地緩存。SqlSession對象中包含一個Executor對象,Executor對象中包含一個PerpetualCache對象,在該對象存放一級緩存數(shù)據(jù)。
由于一級緩存是在SqlSession對象中,所以只有使用同一個SqlSession對象操作數(shù)據(jù)庫時才能共享一級緩存。
MyBatis的一級緩存是默認(rèn)開啟的,不需要任何的配置。
如下圖所示:
(1)測試一級緩存
其實測試方法很簡單,就是通過使用相同和不同的SqlSession對象進行SQL查詢,返回的對象的哈希值是否一樣就可以知道了,如果返回的哈希值一樣說明沒有進行SQL查詢,而是直接從緩存拿到對象來返回
下面是使用相同的Session對象來執(zhí)行查詢,如果觀察user1和user2的哈希值一樣則說明確實開啟了一級緩存,并沒有進行查詢,而是直接從緩存中拿數(shù)據(jù)。
import com.mybatisstudy.mapper.UserMapper; import com.mybatisstudy.pojo.User; import org.apache.ibatis.io.Resources; import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory; import org.apache.ibatis.session.SqlSessionFactoryBuilder; import org.junit.Test; import java.io.InputStream; public class TestUserMapper3 { // 測試使用同一個SqlSession查詢 @Test public void testCache1() throws Exception{ InputStream is = Resources.getResourceAsStream("SqlMapConfig.xml"); SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder(); SqlSessionFactory factory = builder.build(is); SqlSession session = factory.openSession(); // 使用同一個SqlSession查詢 UserMapper mapper1 = session.getMapper(UserMapper.class); UserMapper mapper2 = session.getMapper(UserMapper.class); User user1 = mapper1.findById(1); System.out.println(user1.hashCode()); System.out.println("------------------------------------------"); User user2 = mapper2.findById(1); System.out.println(user2.hashCode()); session.close(); } }
執(zhí)行結(jié)果
OK,確實返回的哈希值都是一樣的,并且我們可以通過控制臺輸出顯示它并沒有進行查詢而是直接從緩存中拿到對象并返回,所以這就是一級緩存 ,提高了查詢效率。
下面使用不同的SqlSession來進行測試一下,返回的哈希值是否一致
// 測試使用不同SqlSession查詢 @Test public void testCache2() throws Exception{ InputStream is = Resources.getResourceAsStream("SqlMapConfig.xml"); SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder(); SqlSessionFactory factory = builder.build(is); SqlSession session1 = factory.openSession(); SqlSession session2 = factory.openSession(); // 測試使用不同SqlSession查詢 UserMapper mapper1 = session1.getMapper(UserMapper.class); UserMapper mapper2 = session2.getMapper(UserMapper.class); User user1 = mapper1.findById(1); System.out.println(user1.hashCode()); System.out.println("---------------------------------"); User user2 = mapper2.findById(1); System.out.println(user2.hashCode()); session1.close(); session2.close(); }
運行結(jié)果
OK,可以看到,返回的哈希值不一樣,并且從控制臺輸出顯示也可以看到這里的確也進行了一次查詢,因此可以證實,共享一級緩存確實是基于SqlSession對象的
(2)清空一級緩存
但是吧,如果緩存過多的話,也是會影響我們的查詢效率的,所以這時候就需要清空緩存了,就像我們時不時要清理一下手機緩存否則就會很卡,是同樣的道理,那怎么清空一級緩存呢?
進行以下操作可以清空MyBatis一級緩存:
- SqlSession 調(diào)用 close() :操作后SqlSession對象不可用,該對象的緩存數(shù)據(jù)也不可用。
- SqlSession 調(diào)用 clearCache() / commit() :操作會清空一級緩存數(shù)據(jù)。
- SqlSession 調(diào)用增刪改方法:操作會清空一級緩存數(shù)據(jù),因為增刪改后數(shù)據(jù)庫發(fā)生改變,緩存數(shù)據(jù)將不準(zhǔn)確
// 清空Mybatis一級緩存 @Test public void testCache3() throws Exception{ InputStream is = Resources.getResourceAsStream("SqlMapConfig.xml"); SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder(); SqlSessionFactory factory = builder.build(is); SqlSession session = factory.openSession(); UserMapper mapper1 = session.getMapper(UserMapper.class); UserMapper mapper2 = session.getMapper(UserMapper.class); User user1 = mapper1.findById(1); System.out.println(user1.hashCode()); // 清空Mybatis一級緩存 session.clearCache(); System.out.println("-------------------------------"); User user2 = mapper2.findById(1); System.out.println(user2.hashCode()); session.close(); }
執(zhí)行效果
OK,返回的哈希值也確實不一樣, 但是我們有沒有觀察到這和上面使用不同的SqlSession對象來執(zhí)行查詢的時候,控制臺輸入顯示有點不一樣,那就是這里不用再建立JDBC連接,也有效了提高查詢效率,所以我們偶爾還是要清空一下緩存才行
三、Mybatis二級緩存
MyBatis二級緩存也叫全局緩存。數(shù)據(jù)存放在SqlSessionFactory中,只要是同一個工廠對象創(chuàng)建的SqlSession,在進行查詢時都能共享數(shù)據(jù)。一般在項目中只有一個SqlSessionFactory對象,所以二級緩存的數(shù)據(jù)是全項目共享的。
MyBatis一級緩存存放的是對象,二級緩存存放的是對象的數(shù)據(jù)。所以要求二級緩存存放的POJO必須是可序列化的,也就是要實現(xiàn)Serializable接口。
MyBatis二級緩存默認(rèn)不開啟,手動開啟后數(shù)據(jù)先存放在一級緩存中,只有一級緩存數(shù)據(jù)清空后,數(shù)據(jù)才會存到二級緩存中。
SqlSession 調(diào)用 clearCache() 無法將數(shù)據(jù)存到二級緩存中。
(1)開啟二級緩存
1. POJO類實現(xiàn)Serializable接口
import java.io.Serializable; public class User implements Serializable { private int id; private String username; private String sex; private String address; }
2. 在Mybatis配置文件添加如下設(shè)置
<!-- 二級緩存打開 --> <settings> <setting name="cacheEnabled" value="true"/> </settings>
這里有個額外知識,就是Mybatis配置文件的標(biāo)簽還得按照順序來放的,否則就會以下編譯錯誤;
The content of element type "configuration" must match "(properties?,settings?,typeAliases?,typeHandlers?,objectFactory?,
objectWrapperFactory?,reflectorFactory?,plugins?,environments?,
databaseIdProvider?,mappers?)".
同時也說明了放置順序就得按照match里面的順序來放
3. 添加 <cache /> 標(biāo)簽
如果查詢到的集合中對象過多,二級緩存只能緩存1024個對象引用。可以通過
<cache /> 標(biāo)簽的size屬性修改該數(shù)量。
比如:<cache size="2048"/>
(2)測試二級緩存
那怎么測試呢,從上面我們可以知道二級緩存存放的是對象的數(shù)據(jù),并且是基于SqlSessionFactory的,因此我們可以用SqlSessionFactory獲取兩個SqlSession對象,然后讓他們分別獲取各自的mapper,然后進行查詢,返回到同一個實例化的USer對象中,如果返回的數(shù)據(jù)是一致的,但是對象的哈希值是不一樣的話,則說明二級緩存里存放的確實對象的數(shù)據(jù)而不是對象。
// 測試二級緩存 @Test public void testCache4() throws Exception { InputStream is = Resources.getResourceAsStream("SqlMapConfig.xml"); SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder(); SqlSessionFactory factory = builder.build(is); SqlSession session = factory.openSession(); UserMapper mapper1 = session.getMapper(UserMapper.class); UserMapper mapper2 = session.getMapper(UserMapper.class); User user1 = mapper1.findById(1); System.out.println(user1); System.out.println(user1.hashCode()); // 讓一級緩存失效 session.commit(); System.out.println("----------------------------"); user1 = mapper2.findById(1); System.out.println(user1); System.out.println(user1.hashCode()); }
運行結(jié)果
OK,從運行結(jié)果上我們可以知道結(jié)果集返回到同一個對象中,而他們的哈希值反而不一樣,說明執(zhí)行第二次查詢的時候新建了一個對象并且該對象指向那個對象并且將SqlSessionFactory中的數(shù)據(jù)賦值到新建的那個對象。其實從控制臺打印的日志我們也可以得出,并沒有執(zhí)行查詢方法,因為沒有打印SQL語句,而且緩存也是從0.0改成了0.5,因此我們可以斷定二級緩存存放的是數(shù)據(jù)而不是對象。
到此這篇關(guān)于Java Mybatis一級緩存和二級緩存的文章就介紹到這了,更多相關(guān)Mybatis一級緩存和二級緩存內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
詳解Java是如何通過接口來創(chuàng)建代理并進行http請求
今天給大家?guī)淼闹R是關(guān)于Java的,文章圍繞Java是如何通過接口來創(chuàng)建代理并進行http請求展開,文中有非常詳細(xì)的介紹及代碼示例,需要的朋友可以參考下2021-06-06在RabbitMQ中實現(xiàn)Work queues工作隊列模式
這篇文章主要介紹了如何在RabbitMQ中實現(xiàn)Work queues模式,代碼詳細(xì),解釋清晰,可以幫助大家更好理解java,對這方面感興趣的朋友可以參考下2021-04-04簡單說說Java SE、Java EE、Java ME三者之間的區(qū)別
本篇文章小編就為大家簡單說說Java SE、Java EE、Java ME三者之間的區(qū)別。需要的朋友可以過來參考下,希望對大家有所幫助2013-10-10mybatis調(diào)用存儲過程,帶in、out參數(shù)問題
這篇文章主要介紹了mybatis調(diào)用存儲過程,帶in、out參數(shù)問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-01-01Spring引入外部屬性文件配置數(shù)據(jù)庫連接的步驟詳解
這篇文章主要介紹了Spring引入外部屬性文件配置數(shù)據(jù)庫連接的步驟詳解,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2021-01-01