mybatis查詢緩存(一、二級緩存)


什么是查詢緩存?

  緩存是介於應用程序和物理數據源之間

  mybatis提供查詢緩存,用於減輕數據壓力,提高數據庫性能。

  mybaits提供一級緩存,和二級緩存。

  

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

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

 

為什么要用緩存?

如果緩存中有數據就不用從數據庫中獲取,減少了和數據之間的交互次數,大大提高系統的性能

為什么會兩種緩存方式?

  二級緩存與一級緩存區別,二級緩存的范圍更大,多個sqlSession可以共享一個UserMapper的二級緩存區域。

 

  • 一級緩存

    • 一級緩存工作原理

      命中條件

      緩存存在一個hash表中,通過查詢SQL,查詢數據庫,客戶端協議等作為key.在判斷是否命中前,MySQL不會解析SQL,而是直接使用SQL去查詢緩存,SQL任何字符上的不同,如空格,注釋,都會導致緩存不命中.

      如果查詢中有不確定數據,例如CURRENT_DATE()和NOW()函數,那么查詢完畢后則不會被緩存.所以,包含不確定數據的查詢是肯定不會找到可用緩存的

    1. 服務器接收SQL,以SQL和一些其他條件為key查找緩存表(額外性能消耗)

    2. 如果找到了緩存,則直接返回緩存(性能提升)

    3. 如果沒有找到緩存,則執行SQL查詢,包括原來的SQL解析,優化等.

    4. 執行完SQL查詢結果以后,將SQL查詢結果存入緩存表(額外性能消耗)

    

 為什么sqlSession去執行commit操作(執行插入、更新、刪除),清空SqlSession中的一級緩存,目的為了讓緩存中存儲的是最新的信息,

  避免臟讀。(所謂的臟數據)

    • 一級緩存測試

    mybatis默認支持一級緩存,不需要在配置文件去配置。

  測試代碼

 1 // 一級緩存測試
 2 @Test
 3 public void testCache1() throws Exception {
 4     SqlSession sqlSession = sqlSessionFactory.openSession();// 創建代理對象
 5     UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
 6 
 7     // 下邊查詢使用一個SqlSession
 8     // 第一次發起請求,查詢id為1的用戶
 9     User user1 = userMapper.getUserById(1);
10     System.out.println(user1);
11 
12     // 如果sqlSession去執行commit操作(執行插入、更新、刪除),清空SqlSession中的一級緩存,這樣做的目的為了讓緩存中存儲的是最新的信息,避免臟讀。
13 
14     // 更新user1的信息
15     // user1.setUsername("我是測試用戶");
16     // userMapper.updateUser(user1);
17     // //執行commit操作去清空緩存
18     // sqlSession.commit();
19 
20     // 第二次發起請求,查詢id為1的用戶
21     User user2 = userMapper.getUserById(1);
22     System.out.println(user2);
23 
24     sqlSession.close();
25 
26 }

  假設我們不執行更新操作,輸出:

 1 DEBUG [main] - Opening JDBC Connection
 2 DEBUG [main] - Created connection 110771485.
 3 DEBUG [main] - Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@69a3d1d]
 4 DEBUG [main] - ==>  Preparing: SELECT * FROM user WHERE id=? 
 5 DEBUG [main] - ==> Parameters: 1(Integer)
 6 DEBUG [main] - <==      Total: 1
 7 User [id=1, username=張三, sex=男]
 8 User [id=1, username=張三, sex=男]
 9 DEBUG [main] - Resetting autocommit to true on JDBC Connection [com.mysql.jdbc.JDBC4Connection@69a3d1d]
10 DEBUG [main] - Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection@69a3d1d]
11 DEBUG [main] - Returned connection 110771485 to pool.

  使用上面更新的代碼,輸出:

 1 DEBUG [main] - Opening JDBC Connection
 2 DEBUG [main] - Created connection 110771485.
 3 DEBUG [main] - Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@69a3d1d]
 4 DEBUG [main] - ==>  Preparing: SELECT * FROM user WHERE id=? 
 5 DEBUG [main] - ==> Parameters: 1(Integer)
 6 DEBUG [main] - <==      Total: 1
 7 User [id=1, username=張三, sex=男]
 8 DEBUG [main] - ==>  Preparing: update user set username=?,sex=? where id=? 
 9 DEBUG [main] - ==> Parameters: 我是測試用戶(String),  null, 1(Integer)
10 DEBUG [main] - <==    Updates: 1
11 DEBUG [main] - Committing JDBC Connection [com.mysql.jdbc.JDBC4Connection@69a3d1d]
12 DEBUG [main] - ==>  Preparing: SELECT * FROM user WHERE id=? 
13 DEBUG [main] - ==> Parameters: 1(Integer)
14 DEBUG [main] - <==      Total: 1
15 User [id=1, username= 我是測試用戶, sex=男]
16 DEBUG [main] - Resetting autocommit to true on JDBC Connection [com.mysql.jdbc.JDBC4Connection@69a3d1d]
17 DEBUG [main] - Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection@69a3d1d]
18 DEBUG [main] - Returned connection 110771485 to pool.

  原來用戶名為張三則更新為我是測試用戶

    • 一級緩存應用

    正式開發,假如項目是將mybatis和spring進行整合開發....,事務控制在service中。

     一個service方法中包括 很多mapper方法調用。   

 1 service{
 2 
 3      //開始執行時,開啟事務,創建SqlSession對象
 4 
 5      //第一次調用mapper的方法getUserById(1)
 6 
 7        //第二次調用mapper的方法getUserById(1),從一級緩存中取數據
 8 
 9      //方法結束,sqlSession關閉
10 
11     }

 

如果是執行兩次service調用查詢相同 的用戶信息,不走一級緩存,因為session方法結束,sqlSession就關閉,一級緩存就清空。

    • 緩存數據失效時機 

      在表的結構或數據發生改變時,查詢緩存中的數據不再有效。有這些INSERT、UPDATE、 DELETE、TRUNCATE、ALTER TABLE、

      DROP TABLE或DROP DATABASE會導致緩存數據失效。所以查詢緩存適合有大量相同查詢的應用,不適合有大量數據更新的應用。

 

    • 可以使用下面三個SQL來清理查詢緩存: 
    1、FLUSH QUERY CACHE; // 清理查詢緩存內存碎片。
    2、RESET QUERY CACHE; // 從查詢緩存中移出所有查詢。
    3、FLUSH TABLES; //關閉所有打開的表,同時該操作將會清空查詢緩存中的內容。
 
  • 二級緩存

    • 二級緩存的工作原理

      第一步:首先開啟mybatis的二級緩存。

      第二步:sqlSession1去查詢用戶id為1的用戶信息,查詢到用戶信息會將查詢數據存儲到二級緩存中。

      第三步:如果SqlSession3去執行相同 mapper下sql,執行commit提交,清空該 mapper下的二級緩存區域的數據。

      第四步:sqlSession2去查詢用戶id為1的用戶信息,去緩存中找是否存在數據,如果存在直接從緩存中取出數據。      

      UserMapper有一個二級緩存區域(按namespace分) ,其它mapper也有自己的二級緩存區域(按namespace分)。

      每一個namespace的mapper都有一個二緩存區域,兩個mapper的namespace如果相同,這兩個mapper執行sql查詢

      到數據將存在相同的二級緩存區域中。

 

 

    • 開啟二級緩存

    mybaits的二級緩存是mapper范圍級別,除了在SqlMapConfig.xml設置二級緩存的總開關,還要在具體的mapper.xml中開啟二級緩存。

     第一步:在核心配置文件mybatis-config.xml中加入以下代碼    

1 <!-- 全局參數的配置 -->
2     <settings>
3         <!-- 開啟二級緩存 -->
4             <setting name="cacheEnabled" value="true"/>
5     </settings> 

  cacheEnabled:對在此配置文件下的所有cache 進行全局性開/關設置。默認true

  

    第二步:實體類User實現序列化接口

 

1 public class User implements Serializable{
2      ......
3        
4 }    

  目的:為了將緩存數據取出執行反序列化操作,因為二級緩存數據存儲介質多種多樣,不一樣在內存。

  第三步:使用Junit進行測試:

 1 // 二級緩存測試
 2     @Test
 3     public void testCache2() throws Exception {
 4         SqlSession sqlSession1 = sqlSessionFactory.openSession();
 5         SqlSession sqlSession2 = sqlSessionFactory.openSession();
 6         SqlSession sqlSession3 = sqlSessionFactory.openSession();
 7        
 8  // 創建代理對象
 9         UserMapper userMapper1 = sqlSession1.getMapper(UserMapper.class);
10         // 第一次發起請求,查詢id為1的用戶
11         User user1 = userMapper1.getUserById(1);
12         System.out.println(user1);
13         
14         //這里執行關閉操作,將sqlsession中的數據寫到二級緩存區域
15         sqlSession1.close();
16         
17         
18         //使用sqlSession3執行commit()操作
19         UserMapper userMapper3 = sqlSession3.getMapper(UserMapper.class);
20         User user  = userMapper3.getUserById(1);
21         user.setUsername("張明明");        
       userMapper3.updateUser(user);
22 //執行提交,清空UserMapper下邊的二級緩存 23 sqlSession3.commit(); 24 sqlSession3.close(); 25 26 UserMapper userMapper2 = sqlSession2.getMapper(UserMapper.class); 27 // 第二次發起請求,查詢id為1的用戶 28 User user2 = userMapper2.getUserById(1); 29 System.out.println(user2); 30 31 sqlSession2.close(); 32 33 }

 

    • 禁用二級緩存

    在statement中設置useCache=false可以禁用當前select語句的二級緩存,即每次查詢都會發出sql去查詢,

    默認情況是true,即該sql使用二級緩存。

       <select id="findOrderListResultMap" resultMap="ordersUserMap" useCache="false"> 

 

    • 刷新緩存

    在mapper的同一個namespace中,如果有其它insert、update、delete操作數據后需要刷新緩存,如果不執行刷新緩存會出現臟讀。

     設置statement配置中的flushCache="true" 屬性,默認情況下為true即刷新緩存,如果改成false則不會刷新。使用緩存時如果手動

    修改數據庫表中的查詢數據會出現臟讀。

    如下:

       <insert id="insertUser" parameterType="com.mybaits.entity.User" flushCache="true"> 

 

    • 二級緩存應用場景 

    對於訪問多的查詢請求且用戶對查詢結果實時性要求不高,此時可采用mybatis二級緩存技術降低數據庫訪問量,

    提高訪問速度,業務場景比如:耗時較高的統計分析sql、電話賬單查詢sql等。

 

    實現方法如下:通過設置刷新間隔時間,由mybatis每隔一段時間自動清空緩存,根據數據變化頻率設置緩存刷新間

    隔 flushInterval ,比如設置為30分鍾、60分鍾、24小時等,根據需求而定。

 

    • 二級緩存的局限性

     mybatis二級緩存對細粒度的數據級別的緩存實現不好,比如如下需求:對商品信息進行緩存,由於商品信息查詢訪問量大,

    但是要求用戶每次都能查詢最新的商品信息,此時如果使用mybatis的二級緩存就無法實現當一個商品變化時只刷新該商品的緩存

    信息而不刷新其它商品的信息,因為mybaits的二級緩存區域以mapper為單位划分,當一個商品信息變化會將所有商品信息的緩存數據

    全部清空。解決此類問題需要在業務層根據需求對數據有針對性緩存

 

vue是什么?

vue是一個當前很火的js框架。它可以將我們的數據,和顯示數據的DOM文檔進行綁定。一旦綁定以后,DOM和數據將會自動同步。使我們不用在考慮給DOM的某個元素去進行賦值,而是將注意力放在數據模型上。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM