參考:
https://www.cnblogs.com/hopeofthevillage/p/11427438.html
https://blog.csdn.net/llziseweiqiu/article/details/79413130
https://blog.csdn.net/qq_29229567/article/details/80561212
Mybatis的一級緩存和二級緩存的理解以及用法
程序中為什么使用緩存?
先了解一下緩存的概念:原始意義是指訪問速度比一般隨機存取存儲器快的一種RAM,通常它不像系統主存那樣使用DRAM技術,而使用昂貴但較快速的SRAM技術。對於我們編程來說,所謂的緩存,就是將程序
或系統經常要調用的對象(臨時數據)存在內存中,一遍其使用時可以快速調用,不必再去創建新的重復的實例。這樣做可以減少系統的開銷,提高效率。
對緩存有了一定的了解以后就知道了使用緩存是為了減少和數據庫的交互次數,提高執行效率。那么下一個問題來了。什么樣的數據能使用緩存,什么樣的數據不能使用?
這是我們使用緩存必須要明確的事情,實際上適用於緩存的數據:經常查詢並且不經常改變的,並且的數據的正確與否對最終結果影響不大的、不適用於緩存的數據:經常改變的數據,數據的正確與否對最終
結果影響很大的。
Mybatis中的一級緩存和二級緩存到底緩存了什么,緩存了以后又有什么效果,緩存的數據什么時候會被清空?
一級緩存:它指的是Mybatis中sqlSession對象的緩存,當我們執行查詢以后,查詢的結果會同時存入到SqlSession為我們提供的一塊區域中,該區域的結構是一個Map,當我們再次查詢同樣的數據,mybatis會
先去sqlsession中查詢是否有,的話直接拿出來用,當SqlSession對象消失時,mybatis的一級緩存也就消失了,同時一級緩存是SqlSession范圍的緩存,當調用SqlSession的修改、添加、刪除、commit(),close等
方法時,就會清空一級緩存。
二級緩存:他值得是Mybatis中SqlSessionFactory對象的緩存,由同一個SqlSessionFactory對象創建的SqlSession共享其緩存,但是其中緩存的是數據而不是對象,所以從二級緩存再次查詢出得結果的對象與
第一次存入的對象是不一樣的。
通過簡單的例子來加深理解一級緩存和二級緩存。
一級緩存
1.用戶類
public class User implements Serializable{ private Integer id; private String username; private Date birthday; private String sex; private String address; get和set方法省略..... }
2.Dao層
public interface UserDao { /** * 查詢所有的用戶 * * @return */ List<User> findAll(); /** * 根據Id查詢用戶 * * @return */ User findById(Integer id); /** * 更新用戶 * @param user */ void updateUser(User user); }
3.UserDao.xml映射文件
<mapper namespace="com.example.dao.UserDao"> <select id="findAll" resultType="com.example.domain.User"> SELECT * FROM USER; </select> <select id="findById" resultType="com.example.domain.User" parameterType="INT"> SELECT * FROM USER WHERE ID = #{ID} </select> <update id="updateUser" parameterType="com.example.domain.User"> update USER <set> <if test="username != null">username=#{username},</if> <if test="password != null">birthday=#{birthday},</if> <if test="sex != null">sex=#{sex},</if> <if test="address != null">address=#{address},</if> </set> where id=#{id} </update> </mapper>
在以上三步中這是mybatis的單表操作,下面通過根據用戶ID查詢用戶的操作來觀察一級緩存生效與否的區別
4.測試
(1) 命中一級緩存的情況
測試代碼:
@Test public void findByIdTest(){ session = factory.openSession(); userDao = session.getMapper(UserDao.class); //第一次獲取該用戶 User user1 = userDao.findById(45); System.out.println(user1); 第二次獲取該用戶 User user2 = userDao.findById(45); System.out.println(user2); System.out.println(user1 == user2); session.close(); }
測試結果:
(2)對SqlSession進行清除緩存的操作,即清楚一級緩存,然后再次進行測試。
@Test public void findByIdTest(){ session = factory.openSession(); userDao = session.getMapper(UserDao.class); User user1 = userDao.findById(45); System.out.println(user1); // session.commit(); 調用SqlSession的commit方法清空緩存 user1.setUsername("更新用戶"); user1.setAddress("更新地址"); userDao.updateUser(user1);//通過更新SqlSession清空緩存 User user2 = userDao.findById(45); System.out.println(user2); System.out.println(user1 == user2); session.close(); }
清空緩存的操作很多,可以都試試。測試結果:
二級緩存
再看一下Mybatis二級緩存是如何使用的,第一步讓Mybatis框架支持二級緩存(在Mybatis的主配置文件中配置),第二步讓當前的映射文件支持二級緩存(在Dao.xml映射文件中配置),第三步讓當前的方法支持二級緩存(在標簽中配置)。根據這個步驟將上面的查詢用戶的接口通過配置改造為可以支持二級緩存的方法。
1.配置Mybatis框架支持二級緩存
<setting name="cacheEnabled" value="true"/>
2.配置UserDao.xml支持二級緩存
<cache/>
3.配置查詢的方法支持二級緩存
<select id="findById" resultType="com.example.domain.User" parameterType="INT" useCache="true"> SELECT * FROM USER WHERE ID = #{ID} </select>
4.測試
@Test public void findByIdTest(){ //第一次查詢 並更新二級緩存 SqlSession session1 = factory.openSession(); UserDao userDao1 = session1.getMapper(UserDao.class); User user1 = userDao1.findById(45); System.out.println(user1); session1.commit(); //commit()方法提交二級緩存 同時清空一級緩存 session1.close();// // user1.setUsername("更新用戶"); // user1.setAddress("更新地址"); // userDao.updateUser(user1);//通過更新SqlSession清空緩存 //第二次查找命中二級緩存 SqlSession session2 = factory.openSession(); UserDao userDao2 = session2.getMapper(UserDao.class); User user2 = userDao2.findById(45); session2.commit(); //commit()方法提交二級緩存 同時清空一級緩存 session2.close();// System.out.println(user2); System.out.println(user1 == user2); }
測試結果:
總結:mybatis的的一級緩存是SqlSession級別的緩存,一級緩存緩存的是對象,當SqlSession提交、關閉以及其他的更新數據庫的操作發生后,一級緩存就會清空。二級緩存是SqlSessionFactory級別的緩存,同一個SqlSessionFactory產生的SqlSession都共享一個二級緩存,二級緩存中存儲的是數據,當命中二級緩存時,通過存儲的數據構造對象返回。查詢數據的時候,查詢的流程是二級緩存>一級緩存>數據庫。
Mybatis的一級緩存和二級緩存的理解和區別
一級緩存基於sqlSession默認開啟,在操作數據庫時需要構造SqlSession對象,在對象中有一個HashMap用於存儲緩存數據。不同的SqlSession之間的緩存數據區域是互相不影響的。
一級緩存的作用域是SqlSession范圍的,當在同一個sqlSession中執行兩次相同的sql語句時,第一次執行完畢會將數據庫中查詢的數據寫到緩存(內存),
第二次查詢時會從緩存中獲取數據,不再去底層數據庫查詢,從而提高查詢效率。
需要注意的是,如果SqlSession執行了DML操作(增刪改),並且提交到數據庫,MyBatis則會清空SqlSession中的一級緩存,這樣做的目的是為了保證緩存中存儲的是最新的信息,避免出現臟讀現象。
當一個SqlSession結束后該SqlSession中的一級緩存也就不存在了。
關閉一級緩存后,再次訪問,需要再次獲取一級緩存,然后才能查找數據,否則會拋出異常。
二級緩存是mapper級別的緩存。使用二級緩存時,多個SqlSession使用同一個Mapper的sql語句去操作數據庫,得到的數據會存在二級緩存區域,它同樣是使用HashMap進行數據存儲。相比一級緩存SqlSession,二級緩存的范圍更大,多個Sqlsession可以共用二級緩存,二級緩存是跨SqlSession的。
二級緩存的作用域是mapper的同一個namespace。不同的sqlSession兩次執行相同的namespace下的sql語句,且向sql中傳遞的參數也相同,即最終執行相同的sql語句,則第一次執行完畢會將數據庫中查詢的數據寫到緩存,第二次查詢會從緩存中獲取數據,不再去底層數據庫查詢,從而提高效率。
在MyBatis配置文件(mybatis-config.xml)中開啟二級緩存(詳細過程自己百度搜索開啟)
//value屬性默認為false
在**Mapper.xml中開啟當前mapper的namespace下的二級緩存
代表創建了一個LRU緩存,並每隔60秒刷新,最大存儲512個對象,而且返回的對象被認為是只讀的。
(1)LRU最近最少使用策略,一處做長時間不被使用的對象。
(2)FIFO先進先出策略,按對象進入緩存的順序來移除它們。
(3)SOFT軟引用策略,移除基於垃圾回收器狀態和軟引用規則的對象。
(4)WEAK弱引用策略,更積極地移除基於垃圾收集器狀態和弱引用規則的對象
CPU中的一級緩存,二級緩存,三級緩存
緩存又叫高速緩沖存儲器,其作用在於緩解主存速度慢、跟不上CPU讀寫速度要求的矛盾。
緩存的實現原理,是把CPU最近最可能用到的少量信息(數據或指令)從主存復制到CACHE中,當CPU下次再用這些信息時,它就不必訪問慢速的主存,而直接從快速的CACHE中得到,從而提高了得到這些信息的速度,使CPU有更高的運行效率。
緩存的工作原理:是當CPU要讀取一個數據時,首先從緩存中查找,如果找到就立即讀取並送給CPU處理;如果沒有找到,就用相對慢的速度從內存中讀取並送給CPU處理,同時把這個數據所在的數據塊調入緩存中,可以使得以后對整塊數據的讀取都從緩存中進行,不必再調用內存。正是這樣的讀取機制使CPU讀取緩存的命中率非常高(大多數CPU可達90%左右),也就是說CPU下一次要讀取的數據90%都在緩存中,只有大約10%需要從內存讀取。這大大節省了CPU直接讀取內存的時間,也使CPU讀取數據時基本無需等待。總的來說,CPU讀取數據的順序是先緩存后內存。
緩存的大小:一般說來,更大一點的cache容量,對提高命中率是有好處的,由於cache是用價格很高的靜態存儲器SRAM器件實現的,而cache容量達到一定大小后,再增加其容量,對命中率的提高並不明顯,從合理的性能/價格比考慮,cache的容量設置應在一個合理的容量范圍之內。
緩存要分一級二級 三級,是為了建立一個層次存儲結構,以達到最高性價比。而且多級組織還可以提高cache的命中率,提高執行效能。
一般來說,一級緩存可以分為一級數據緩存(Data Cache,D-Cache)和一級指令緩存(InstructionCache,I-Cache)。二者分別用來存放數據以及對執行這些數據的指令進行即時解碼,而且兩者可以同時被CPU訪問,減少了爭用Cache所造成的沖突,提高了處理器效能。
目前大多數CPU的一級數據緩存和一級指令緩存具有相同的容量,例如AMD的Athlon。XP就具有64KB的一級數據緩存和64KB的一級指令緩存,其一級緩存就以64KB+64KB來表示,其余的CPU的一級緩存表示方法以此類推。並不是緩存越大越好,譬如AMD和INTER就有不同的理論,AMD認為一級緩存越大越好,所以一級比較大,而INTER認為過大會有更長的指令執行時間,所以一級很小,二級緩存那兩個公司的理論又反過來了,AMD的小,INTER的大,一般主流的INTERCPU的2級緩存都在2M左右,我們通常用(L1,L2)來稱呼。
CPU緩存(CacheMemory)是位於CPU與內存之間的臨時存儲器,它的容量比內存小的多,但是交換速度卻比內存要快得多。緩存的出現主要是為了解決CPU運算速度與內存讀寫速度不匹配的矛盾,因為CPU運算速度要比內存讀寫速度快很多,這樣會使CPU花費很長時間等待數據到來或把數據寫入內存。在緩存中的數據是內存中的一小部分,但這一小部分是短時間內CPU即將訪問的,當CPU調用大量數據時,就可避開內存直接從緩存中調用,從而加快讀取速度。由此可見,在CPU中加入緩存是一種高效的解決方案,這樣整個內存儲器(緩存+內存)就變成了既有緩存的高速度,又有內存的大容量的存儲系統了。緩存對CPU的性能影響很大,主要是因為CPU的數據交換順序和CPU與緩存間的帶寬引起的。
根據數據讀取順序和與CPU結合的緊密程度,CPU緩存可以分為一級緩存,二級緩存,部分高端CPU還具有三級緩存,每一級緩存中所儲存的全部數據都是下一級緩存的一部分,這三種緩存的技術難度和制造成本是相對遞減的,所以其容量也是相對遞增的。當CPU要讀取一個數據時,首先從一級緩存中查找,如果沒有找到再從二級緩存中查找,如果還是沒有就從三級緩存或內存中查找。
一般來說,每級緩存的命中率大概都在80%左右,也就是說全部數據量的80%都可以在一級緩存中找到,只剩下20%的總數據量才需要從二級緩存、三級緩存或內存中讀取,由此可見一級緩存是整個CPU緩存架構中最為重要的部分。
目前緩存基本上都是采用SRAM存儲器,SRAM是英文StaticRAM的縮寫,它是一種具有靜志存取功能的存儲器,不需要刷新電路即能保存它內部存儲的數據。不像DRAM內存那樣需要刷新電路,每隔一段時間,固定要對DRAM刷新充電一次,否則內部的數據即會消失,因此SRAM具有較高的性能,但是SRAM也有它的缺點,即它的集成度較低,相同容量的DRAM內存可以設計為較小的體積,但是SRAM卻需要很大的體積,這也是目前不能將緩存容量做得太大的重要原因。
它的特點歸納如下:優點是節能、速度快、不必配合內存刷新電路、可提高整體的工作效率,缺點是集成度低、相同的容量體積較大、而且價格較高,只能少量用於關鍵性系統以提高效率。