Mybatis 詳解--- 一級緩存、二級緩存

Mybatis 爲我們提供了一級緩存和二級緩存,可以通過下圖來理解:
Mybatis 詳解--- 一級緩存、二級緩存

①、一級緩存是SqlSession級別的緩存。在操作數據庫時需要構造sqlSession對象,在對象中有一個數據結構(HashMap)用於存儲緩存數據。不同的sqlSession之間的緩存數據區域(HashMap)是互相不影響的。

②、二級緩存是mapper級別的緩存,多個SqlSession去操作同一個Mapper的sql語句,多個SqlSession可以共用二級緩存,二級緩存是跨SqlSession的。

1、一級緩存

①、我們在一個 sqlSession 中,對 User 表根據id進行兩次查詢,查看他們發出sql語句的情況。

@Test

public void testSelectOrderAndUserByOrderId(){

//根據 sqlSessionFactory 產生 session

SqlSession sqlSession = sessionFactory.openSession();

String statement = "one.to.one.mapper.OrdersMapper.selectOrderAndUserByOrderID";

UserMapper userMapper = sqlSession.getMapper(UserMapper.class);

//第一次查詢,發出sql語句,並將查詢的結果放入緩存中

User u1 = userMapper.selectUserByUserId(1);

System.out.println(u1);

//第二次查詢,由於是同一個sqlSession,會在緩存中查找查詢結果

//如果有,則直接從緩存中取出來,不和數據庫進行交互

User u2 = userMapper.selectUserByUserId(1);

System.out.println(u2);

sqlSession.close();

}

查看控制檯打印情況:
Mybatis 詳解--- 一級緩存、二級緩存

②、 同樣是對user表進行兩次查詢,只不過兩次查詢之間進行了一次update操作。

@Test

public void testSelectOrderAndUserByOrderId(){

//根據 sqlSessionFactory 產生 session

SqlSession sqlSession = sessionFactory.openSession();

String statement = "one.to.one.mapper.OrdersMapper.selectOrderAndUserByOrderID";

UserMapper userMapper = sqlSession.getMapper(UserMapper.class);

//第一次查詢,發出sql語句,並將查詢的結果放入緩存中

User u1 = userMapper.selectUserByUserId(1);

System.out.println(u1);

//第二步進行了一次更新操作,sqlSession.commit()

u1.setSex("女");

userMapper.updateUserByUserId(u1);

sqlSession.commit();

//第二次查詢,由於是同一個sqlSession.commit(),會清空緩存信息

//則此次查詢也會發出 sql 語句

User u2 = userMapper.selectUserByUserId(1);

System.out.println(u2);

sqlSession.close();

}

控制檯打印情況:
Mybatis 詳解--- 一級緩存、二級緩存

③、總結

1、第一次發起查詢用戶id爲1的用戶信息,先去找緩存中是否有id爲1的用戶信息,如果沒有,從數據庫查詢用戶信息。得到用戶信息,將用戶信息存儲到一級緩存中。

2、如果中間sqlSession去執行commit操作(執行插入、更新、刪除),則會清空SqlSession中的一級緩存,這樣做的目的爲了讓緩存中存儲的是最新的信息,避免髒讀。

3、第二次發起查詢用戶id爲1的用戶信息,先去找緩存中是否有id爲1的用戶信息,緩存中有,直接從緩存中獲取用戶信息。
Mybatis 詳解--- 一級緩存、二級緩存

2、二級緩存

二級緩存的原理和一級緩存原理一樣,第一次查詢,會將數據放入緩存中,然後第二次查詢則會直接去緩存中取。但是一級緩存是基於 sqlSession 的,而 二級緩存是基於 mapper文件的namespace的,也就是說多個sqlSession可以共享一個mapper中的二級緩存區域,並且如果兩個mapper的namespace相同,即使是兩個mapper,那麼這兩個mapper中執行sql查詢到的數據也將存在相同的二級緩存區域中。
Mybatis 詳解--- 一級緩存、二級緩存

那麼二級緩存是如何使用的呢?

①、開啓二級緩存

和一級緩存默認開啓不一樣,二級緩存需要我們手動開啓

首先在全局配置文件 mybatis-configuration.xml 文件中加入如下代碼:

其次在 UserMapper.xml 文件中開啓緩存 我們可以看到 mapper.xml 文件中就這麼一個空標籤,其實這裏可以配置,PerpetualCache這個類是mybatis默認實現緩存功能的類。我們不寫type就使用mybatis默認的緩存,也可以去實現 Cache 接口來自定義緩存。 ![](https://s1.51cto.com/images/blog/201809/14/a43f29e74d0adfd4824f98bad01928c6.png?x-oss-process=image/watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=) ![](https://s1.51cto.com/images/blog/201809/14/eaa98075982747032265a4d8a1dc8153.png?x-oss-process=image/watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=) 我們可以看到 二級緩存 底層還是 HashMap 架構。 ②、po 類實現 Serializable 序列化接口 ![](https://s1.51cto.com/images/blog/201809/14/6f98894d2928359cd7a51f6c81f19e25.png?x-oss-process=image/watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=) 開啓了二級緩存後,還需要將要緩存的pojo實現Serializable接口,爲了將緩存數據取出執行反序列化操作,因爲二級緩存數據存儲介質多種多樣,不一定只存在內存中,有可能存在硬盤中,如果我們要再取這個緩存的話,就需要反序列化了。所以mybatis中的pojo都去實現Serializable接口。 ③、測試 一、測試二級緩存和sqlSession 無關 @Test public void testTwoCache(){ //根據 sqlSessionFactory 產生 session SqlSession sqlSession1 = sessionFactory.openSession(); SqlSession sqlSession2 = sessionFactory.openSession(); String statement = "com.ys.twocache.UserMapper.selectUserByUserId"; UserMapper userMapper1 = sqlSession1.getMapper(UserMapper.class); UserMapper userMapper2 = sqlSession2.getMapper(UserMapper.class); //第一次查詢,發出sql語句,並將查詢的結果放入緩存中 User u1 = userMapper1.selectUserByUserId(1); System.out.println(u1); sqlSession1.close();//第一次查詢完後關閉sqlSession //第二次查詢,即使sqlSession1已經關閉了,這次查詢依然不發出sql語句 User u2 = userMapper2.selectUserByUserId(1); System.out.println(u2); sqlSession2.close(); } 可以看出上面兩個不同的sqlSession,第一個關閉了,第二次查詢依然不發出sql查詢語句。 二、測試執行 commit() 操作,二級緩存數據清空 @Test public void testTwoCache(){ //根據 sqlSessionFactory 產生 session SqlSession sqlSession1 = sessionFactory.openSession(); SqlSession sqlSession2 = sessionFactory.openSession(); SqlSession sqlSession3 = sessionFactory.openSession(); String statement = "com.ys.twocache.UserMapper.selectUserByUserId"; UserMapper userMapper1 = sqlSession1.getMapper(UserMapper.class); UserMapper userMapper2 = sqlSession2.getMapper(UserMapper.class); UserMapper userMapper3 = sqlSession2.getMapper(UserMapper.class); //第一次查詢,發出sql語句,並將查詢的結果放入緩存中 User u1 = userMapper1.selectUserByUserId(1); System.out.println(u1); sqlSession1.close();//第一次查詢完後關閉sqlSession //執行更新操作,commit() u1.setUsername("aaa"); userMapper3.updateUserByUserId(u1); sqlSession3.commit(); //第二次查詢,由於上次更新操作,緩存數據已經清空(防止數據髒讀),這裏必須再次發出sql語句 User u2 = userMapper2.selectUserByUserId(1); System.out.println(u2); sqlSession2.close(); } 查看控制檯情況: ![](https://s1.51cto.com/images/blog/201809/14/7e56bf460830a038fd9e68a0c57b322f.png?x-oss-process=image/watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=) ④、useCache和flushCache mybatis中還可以配置userCache和flushCache等配置項,userCache是用來設置是否禁用二級緩存的,在statement中設置useCache=false可以禁用當前select語句的二級緩存,即每次查詢都會發出sql去查詢,默認情況是true,即該sql使用二級緩存。 這種情況是針對每次查詢都需要最新的數據sql,要設置成useCache=false,禁用二級緩存,直接從數據庫中獲取。 在mapper的同一個namespace中,如果有其它insert、update、delete操作數據後需要刷新緩存,如果不執行刷新緩存會出現髒讀。 設置statement配置中的flushCache=”true” 屬性,默認情況下爲true,即刷新緩存,如果改成false則不會刷新。使用緩存時如果手動修改數據庫表中的查詢數據會出現髒讀。 一般下執行完commit操作都需要刷新緩存,flushCache=true表示刷新緩存,這樣可以避免數據庫髒讀。所以我們不用設置,默認即可。 合理利用自己每一分每一秒的時間來學習提升自己,不要再用"沒有時間“來掩飾自己思想上的懶惰!趁年輕,使勁拼,給未來的自己一個交代! 轉:http://blog.itpub.net/31545684/viewspace-2214077/
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章