什么是查詢緩存?
緩存是介於應用程序和物理數據源之間
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來清理查詢緩存:
-
二級緩存
- 二級緩存的工作原理
第一步:首先開啟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的某個元素去進行賦值,而是將注意力放在數據模型上。