mybatis mapper.xml 文件共用_MyBatis 缓存原来是这么一回事儿!| 原力计划
什么是緩存?
緩存就是存儲數據的一個地方(稱作:Cache),當程序要讀取數據時,會首先從緩存中獲取,有則直接返回,否則從其他存儲設備中獲取。
緩存的特點:緩存最重要的一點就是從其內部獲取數據的速度是非常快的,通過
緩存可以加快數據的訪問速度。
Mybatis中的緩存
MyBatis 是一個支持普通 SQL查詢,存儲過程和高級映射的優秀持久層框架。它消除了幾乎所有的JDBC代碼和參數的手工設置以及結果集的檢索,可使用使用簡單的 XML或注解用于配置和原始映射,將接口和 Java 的POJOs(Plain Ordinary Java Objects,普通的 Java對象)映射成數據庫中的記錄。
通常情況下mybatis會訪問數據庫獲取數據,中間涉及到網絡通信,數據庫從磁盤中讀取數據,然后將數據返回給mybatis,總的來說耗時還是挺長的,mybatis為了加快數據查詢的速度,在其內部引入了緩存來加快數據的查詢速度。
mybatis中分為一級緩存和二級緩存:
一級緩存是SqlSession級別的緩存,在操作數據庫時需要構造 sqlSession對象,在對象中有一個數據結構(HashMap)用于存儲緩存數據,不同的sqlSession之間的緩存數據區域是互相不影響的。
二級緩存是mapper級別的緩存,多個SqlSession去操作同一個Mapper的sql語句,多個SqlSession可以共用二級緩存,二級緩存是跨SqlSession的。
Mybatis一級緩存
一級緩存是SqlSession級別的緩存,每個SqlSession都有自己單獨的一級緩存,多個SqlSession之間的一級緩存是相互隔離的,互不影響,mybatis中一級緩存是默認自動開啟的。
一級緩存工作原理:在同一個SqlSession中去多次去執行同樣的查詢,每次執行的時候會先到一級緩存中查找,如果緩存中有就直接返回,如果一級緩存中沒有相關數據,mybatis就會去db中進行查找,然后將查找到的數據放入一級緩存中,第二次執行同樣的查詢的時候,會發現緩存中已經存在了,會直接返回。一級緩存的存儲介質是內存,是用一個HashMap來存儲數據的,所以訪問速度是非常快的。
一級緩存案例
sql源文件如下:
DROP TABLE IF EXISTS `t_student`;CREATE TABLE `t_student` ( `id` int(32) NOT NULL AUTO_INCREMENT, `student_id` int(32) NOT NULL, `student_name` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, `age` int(32) NOT NULL, `gender` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, `class_name` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, PRIMARY KEY (`id`) USING BTREE) ENGINE = InnoDB AUTO_INCREMENT = 6 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;INSERT INTO `t_student` VALUES (1, 2018013001, '張三', 18, '男', '301');INSERT INTO `t_student` VALUES (2, 2018013002, '李四', 19, '男', '301');INSERT INTO `t_student` VALUES (3, 2018013003, '王芳', 18, '女', '302');INSERT INTO `t_student` VALUES (4, 2018013004, '李娟', 19, '女', '301');下面是查詢用戶信息mapper文件內容
select id, student_id, student_name, age, gender, class_name from mybatis.t_student where id = #{id}測試用例
@Test public void testStudentDao() { // 通過工具類生成SqlSession對象 SqlSession session = MybatisUtils.getSession(); // 測試查詢方法 Student stu1 = session.selectOne("com.lwz.mapper.StudentDao.queryById", 1); System.out.println(stu1.getStudentName()); Student stu2 = session.selectOne("com.lwz.mapper.StudentDao.queryById", 1); System.out.println(stu2.getStudentName());System.out.println(stu1 == stu2); session.commit(); session.close(); }上面的代碼在同一個SqlSession中去執行了2次獲取用戶列表信息,2次查詢結果分別放在stu1和stu2,最終代碼中也會判斷這兩個結果是否相等,下面我們運行一下看看會訪問幾次db?
運行輸出:
從輸出中可以看出看到,sql只輸出了一次,說明第一次會訪問數據庫,第二次直接從緩存中獲取的,最后輸出了一個true,也說明兩次返回結果是同一個對象,第二次直接從緩存中獲取數據的,加快了查詢的速度。
清空一級緩存的3種方式
同一個SqlSession中查詢同樣的數據,mybatis默認會從一級緩存中獲取,如果緩存中沒有,才會訪問db,那么我們如何去清除一級緩存呢,強制讓查詢去訪問db呢?
SqlSession中執行增、刪、改操作,此時sqlsession會自動清理其內部的一級緩存;
調用SqlSession中的clearCache方法清理其內部的一級緩存;
設置Mapper xml中select元素的flushCache屬性值為true,那么執行查詢的時候會先清空一級緩存中的所有數據,然后去db中獲取數據
下面我們來分別演示這3種情況
方式1:增刪操作讓一級緩存失效
當執行增刪改操時,mybatis會將當前SqlSession一級緩存中的所有數據都清除。
案例代碼:
@Test public void testStudentDao() { // 通過工具類生成SqlSession對象 SqlSession session = MybatisUtils.getSession(); //第一次查詢 Student stu1 = session.selectOne("com.lwz.mapper.StudentDao.queryById", 1); System.out.println(stu1.getStudentName()); int i = session.delete("com.lwz.mapper.StudentDao.deleteById", 4); System.out.println(i); //第二次查詢 Student stu2 = session.selectOne("com.lwz.mapper.StudentDao.queryById", 1); System.out.println(stu2.getStudentName()); System.out.println(stu1 == stu2); session.commit(); session.close(); }運行輸出:
從輸出中可以看出2次查詢都訪問了db,并且兩次查詢的結果集(false)是不一樣的。刪除數據讓緩存失效是可以理解的,刪除操作可能會改變數據庫中的數據,所以如果再從緩存中去獲取,可能獲取到的數據和db中的數據不一致的情況,mybatis為了避免這種情況,在執行刪除操作的時候,會將SqlSession中的一級緩存清空。插入和修改也是一樣的。
方式2:SqlSession.clearCache清理一級緩存
SqlSession.clearCache()方法會將當前SqlSession一級緩存中的所有數據清除。
案例代碼:
@Test public void testStudentDao() { // 通過工具類生成SqlSession對象 SqlSession session = MybatisUtils.getSession(); //第一次查詢 Student stu1 = session.selectOne("com.lwz.mapper.StudentDao.queryById", 1); System.out.println(stu1.getStudentName()); //調用clearCache方法清理當前SqlSession中的緩存 session.clearCache(); //第二次查詢 Student stu2 = session.selectOne("com.lwz.mapper.StudentDao.queryById", 1); System.out.println(stu2.getStudentName()); System.out.println(stu1 == stu2); session.commit(); session.close(); }運行輸出:
從輸出中可以看出,2次同樣的查詢都訪問了db。
方式3:Select元素的flushCache置為true
將Mapper xml中select元素的flushCache屬性置為true的時候,每次執行這個select元素對應的查詢之前,mybatis會將當前SqlSession中一級緩存中的所有數據都清除。
案例代碼
select id, student_id, student_name, age, gender, class_name from mybatis.t_student where id = #{id}對應測試用例
@Test public void testStudentDao() { // 通過工具類生成SqlSession對象 SqlSession session = MybatisUtils.getSession(); //第一次查詢 Student stu1 = session.selectOne("com.lwz.mapper.StudentDao.queryById", 1); System.out.println(stu1.getStudentName()); //第二次查詢 Student stu2 = session.selectOne("com.lwz.mapper.StudentDao.queryById", 1); System.out.println(stu2.getStudentName()); System.out.println(stu1 == stu2); session.commit(); session.close(); }運行輸出:
從輸出中可以看出,2次同樣的查詢都訪問了db。
一級緩存使用總結
一級緩存是SqlSession級別的,每個人SqlSession有自己的一級緩存,不同的SqlSession之間一級緩存是相互隔離的;
mybatis中一級緩存默認是自動開啟的;
當在同一個SqlSession中執行同樣的查詢的時候,會先從一級緩存中查找,如果找到了直接返回,如果沒有找到會去訪問db,然后將db返回的數據丟到一級緩存中,下次查詢的時候直接從緩存中獲取;
一級緩存清空的3種方式(1:SqlSession中執行增刪改會使一級緩存失效;2:調用SqlSession.clearCache方法會使一級緩存失效;3:Mapper xml中的select元素的flushCache屬性置為true,那么執行這個查詢會使一級緩存失效)
Mybatis二級緩存
二級緩存的使用
一級緩存使用上存在局限性,必須要在同一個SqlSession中執行同樣的查詢,一級緩存才能提升查詢速度,如果想在不同的SqlSession之間使用緩存來加快查詢速度,此時我們需要用到二級緩存了。
二級緩存是mapper級別的緩存,每個mapper xml有個namespace,二級緩存和namespace綁定的,每個namespace關聯一個二級緩存,多個SqlSession可以共用二級緩存,二級緩存是跨SqlSession的。
二級緩存默認是沒有開啟的,需要我們在mybatis全局配置文件中進行開啟:
上面配置好了以后,還需要在對應的mapper xml加上下面配置,表示這個mapper中的查詢開啟二級緩存:
經過上面兩個步驟,就完成了二級緩存的開啟操作。
一二級緩存共存時查詢原理
一二級緩存如果都開啟的情況下,數據查詢過程如下:
當發起一個查詢的時候,mybatis會先訪問這個namespace對應的二級緩存,如果二級緩存中有數據則直接返回,否則繼續向下;
查詢一級緩存中是否有對應的數據,如果有則直接返回,否則繼續向下;
訪問db獲取需要的數據,然后放在當前SqlSession對應的二級緩存中,并且在本地內存中的另外一個地方存儲一份(這個地方我們就叫TransactionalCache);
當SqlSession關閉的時候,也就是調用SqlSession的close方法的時候,此時會將TransactionalCache中的數據放到二級緩存中,并且會清空當前SqlSession一級緩存中的數據。
二級緩存案例
mybatis全局配置文件開啟二級緩存配置
映射文件中使用cache元素開啟二級緩存
select id, student_id, student_name, age, gender, class_name from mybatis.t_student where id = #{id}測試用例
@Testpublic void testStudentDao() { // 通過工具類生成SqlSession對象 SqlSession session = MybatisUtils.getSession(); //第一次查詢 StudentDao studentDao = session.getMapper(StudentDao.class); Student student = studentDao.queryById(1); System.out.println(student.getStudentName()); //關閉session session.close(); SqlSession session1 = MybatisUtils.getSession(); //第二次查詢 StudentDao studentDao1 = session1.getMapper(StudentDao.class); Student student1 = studentDao1.queryById(1); System.out.println(student1.getStudentName());}上面執行了2次查詢,每次查詢都是新的SqlSession,運行一下看看效果。
執行輸出
DEBUG [main] - Cache Hit Ratio [com.lwz.dao.StudentDao]: 0.0DEBUG [main] - ==> Preparing: select id, student_id, student_name, age, gender, class_name from mybatis.t_student where id = ? DEBUG [main] - ==> Parameters: 1(Integer)DEBUG [main] - <== Total: 1張三DEBUG [main] - Cache Hit Ratio [com.lwz.dao.StudentDao]: 0.5張三注意上面第一行日志輸出:
DEBUG [main] - Cache Hit Ratio [com.lwz.dao.StudentDao]: 0.0對這行做一個解釋:com.lwz.dao.StudentDao是上面查詢訪問的mapper xml的namesapce的值,去這個namespace對應的二級緩存中去查詢數據,沒有查詢到,輸出中的0.0表示命中率,這次沒有命中,所以命中率為0。
然后就去db中訪問數據了,會將db中返回的數據放在一級緩存中,第一次運行完畢之后會調用SqlSession的close方法,然后db中返回的數據會被丟到二級緩存中,第二次查詢的時候就直接從二級緩存中獲取到數據返回了,所以第二次查詢輸出如下:
2次查詢都去訪問了二級緩存,第二次命中了,命中率為1/2=0.5
清空或者跳過二級緩存的3種方式
當二級緩存開啟的時候,在某個mapper xml中添加cache元素之后,這個mapper xml中所有的查詢都默認開啟了二級緩存,那么我們如何清空或者跳過二級緩存呢?3種方式如下:
對應的mapper中執行增刪改查會清空二級緩存中數據;
select元素的flushCache屬性置為true,會先清空二級緩存中的數據,然后再去db中查詢數據,然后將數據再放到二級緩存中;
select元素的useCache屬性置為false,可以使這個查詢跳過二級緩存,然后去查詢數據
方式1:增刪改會清除二級緩存中的數據
案例代碼
@Test public void testStudentDao() { // 通過工具類生成SqlSession對象 SqlSession session = MybatisUtils.getSession(); //第一次查詢 StudentDao studentDao = session.getMapper(StudentDao.class); Student student = studentDao.queryById(1); System.out.println(student.getStudentName()); SqlSession session2 = MybatisUtils.getSession(); StudentDao studentDao2 = session2.getMapper(StudentDao.class); Student student3 = new Student(); student3.setAge(10); student3.setStudentName("速度放緩"); student3.setGender("女"); student3.setClassName("303"); student3.setStudentId(2018013456); int i = studentDao2.insert(student3); System.out.println(i); session2.commit(); SqlSession session1 = MybatisUtils.getSession(); //第二次查詢 StudentDao studentDao1 = session1.getMapper(StudentDao.class); Student student1 = studentDao1.queryById(1); System.out.println(student1.getStudentName()); }上面使用了3個不同的SqlSession,第一次和第三次都調用了queryById()執行查詢,中間執行了一個插入操作,mybatis執行插入的時候,會先清除當前namespace對應的二級緩存中的數據,所以上面2次查詢最終都會訪問db,來運行一下看看效果。
運行輸出
方式2:select元素的flushCache屬性置為true
當將mapper xml中select元素的flushCache屬性置為true,會先清空二級緩存中的數據,然后再去db中查詢數據,然后將數據再放到二級緩存中。
select id, student_id, student_name, age, gender, class_name from mybatis.t_student where id = #{id}方式3:select元素的useCache置為false跳過二級緩存,但是不會清空二級緩存數據
select id, student_id, student_name, age, gender, class_name from mybatis.t_student where id = #{id}二級緩存使用總結
一二級緩存訪問順序:一二級緩存都存在的情況下,會先訪問二級緩存,然后再訪問一級緩存,最后才會訪問db,這個順序大家理解一下;
將mapper xml中select元素的flushCache屬性置為false,最終會清除一級緩存所有數據,同時會清除這個select所在的namespace對應的二級緩存中所有的數據;
將mapper xml中select元素的useCache置為false,會使這個查詢跳過二級緩存;
總體上來說使用緩存可以提升查詢效率,這塊知識掌握了,大家可以根據業務自行選擇
版權聲明:本文為CSDN博主「Lw中」的原創文章,遵循CC 4.0 BY-SA版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/weixin_43894879/java/article/details/106044225
更多精彩推薦
?國士無雙:賣掉美國房子,回國創辦姚班,他只為培養一流的程序員!
?對話 SmartX:領跑超融合中高端市場之道——用專注加專業構筑企業云基礎
?過分了!耗資 5600 萬、4 年開發的網絡商城成“爛尾樓”,404 無法打開
?不知道路由器工作原理?沒關系,來這看看!看不懂你捶我 | 原力計劃
?萬字長文帶你入門 GCN
?贈書 | 基于區塊鏈法定貨幣的支付體系,應該怎么做?
你點的每個“在看”,我都認真當成了喜歡總結
以上是生活随笔為你收集整理的mybatis mapper.xml 文件共用_MyBatis 缓存原来是这么一回事儿!| 原力计划的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: hive表指定分区字段搜索_Spark
- 下一篇: cfiledialog指定位置和大小_位