這是mybatis系列第11篇,沒看前文的建議先去【Java冢狐】公眾號中查看前文,方便理解和掌握,
什么是快取?
快取就是存盤資料的一個地方(稱作:Cache),當程式要讀取資料時,會首先從快取中獲取,有則直接回傳,否則從其他存盤設備中獲取,快取最重要的一點就是從其內部獲取資料的速度是非常快的,通過快取可以加快資料的訪問速度,比如我們從db中獲取資料,中間需要經過網路傳輸耗時,db server從磁盤讀取資料耗時等,如果這些資料直接放在jvm對應的記憶體中,訪問是不是會快很多,
mybatis中的快取
mybatis中分為一級快取和二級快取,
- 一級快取是SqlSession級別的快取,在操作資料庫時需要構造 sqlSession物件,在物件中有一個資料結構(HashMap)用于存盤快取資料,不同的sqlSession之間的快取資料區域(HashMap)是互相不影響的,
- 二級快取是mapper級別的快取,多個SqlSession去操作同一個Mapper的sql陳述句,多個SqlSession可以共用二級快取,二級快取是跨SqlSession的,
一級快取
一級快取是SqlSession級別的快取,每個SqlSession都有自己單獨的一級快取,多個SqlSession之間的一級快取是相互隔離的,互不影響,mybatis中一級快取是默認自動開啟的,
一級快取作業原理:在同一個SqlSession中去多次去執行同樣的查詢,每次執行的時候會先到一級快取中查找,如果快取中有就直接回傳,如果一級快取中沒有相關資料,mybatis就會去db中進行查找,然后將查找到的資料放入一級快取中,第二次執行同樣的查詢的時候,會發現快取中已經存在了,會直接回傳,一級快取的存盤介質是記憶體,是用一個HashMap來存盤資料的,所以訪問速度是非常快的,
一級快取案例
案例sql腳本
DROP DATABASE IF EXISTS `mybatisdemo`;
CREATE DATABASE `mybatisdemo`;
USE `mybatisdemo`;
DROP TABLE IF EXISTS user;
CREATE TABLE user(
id int AUTO_INCREMENT PRIMARY KEY COMMENT '用戶id',
name VARCHAR(32) NOT NULL DEFAULT '' COMMENT '用戶名',
age SMALLINT NOT NULL DEFAULT 1 COMMENT '年齡'
) COMMENT '用戶表';
INSERT INTO t_user VALUES (1,'Java冢狐',18),(2,'Java',100),(3,'冢狐',23);
下面是查詢用戶資訊,回傳一個list
<select id="getList1" resultType="com.zhonghu.chat12.demo9.model.UserModel" parameterType="map">
SELECT id,name,age FROM user
<where>
<if test="id!=null">
AND id = #{id}
</if>
<if test="name!=null and name.toString()!=''">
AND name = #{name}
</if>
<if test="age!=null">
AND age = #{age}
</if>
</where>
</select>
對應的mapper介面方法
List<UserModel> getList1(Map<String, Object> paramMap);
測驗用例
com.zhonghu.chat12.demo9.Demo9Test#level1CacheTest1
/**
* 一級快取測驗
*
* @throws IOException
*/
@Test
public void level1CacheTest1() throws IOException {
String mybatisConfig = "demo9/mybatis-config.xml";
this.before(mybatisConfig);
try (SqlSession sqlSession = this.sqlSessionFactory.openSession(true);) {
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
//第一次查詢
List<UserModel> userModelList1 = mapper.getList1(null);
log.info("{}", userModelList1);
//第二次查詢
List<UserModel> userModelList2 = mapper.getList1(null);
log.info("{}", userModelList2);
log.info("{}", userModelList1 == userModelList2);
}
}
上面的代碼在同一個SqlSession中去執行了2次獲取用戶串列資訊,2次查詢結果分別放在userModelList1和userModelList2,最終代碼中也會判斷這兩個集合是否相等,下面我們運行一下看看會訪問幾次db,
運行輸出
01:15.312 [main] DEBUG c.j.c.d.mapper.UserMapper.getList1 - ==> Preparing: SELECT id,name,age FROM user
01:15.340 [main] DEBUG c.j.c.d.mapper.UserMapper.getList1 - ==> Parameters:
01:15.364 [main] DEBUG c.j.c.d.mapper.UserMapper.getList1 - <== Total: 3
01:15.364 [main] INFO c.j.chat05.demo9.Demo9Test - [UserModel(id=1, name=Java冢狐, age=18), UserModel(id=2, name=Java, age=100), UserModel(id=3, name=冢狐, age=23)]
01:15.367 [main] INFO c.j.chat05.demo9.Demo9Test - [UserModel(id=1, name=Java冢狐, age=18), UserModel(id=2, name=Java, age=100), UserModel(id=3, name=冢狐, age=23)]
01:15.367 [main] INFO c.j.chat05.demo9.Demo9Test - true
從輸出中可以看出看到,sql只輸出了一次,說明第一次會訪問資料庫,第二次直接從快取中獲取的,最后輸出了一個true,也說明兩次回傳結果是同一個物件,第二次直接從快取中獲取資料的,加快了查詢的速度,
清空一級快取的3種方式
同一個SqlSession中查詢同樣的資料,mybatis默認會從一級快取中獲取,如果快取中沒有,才會訪問db,那么如果我們希望不走快取而是直接去訪問資料庫,又該如何操作呢?
讓一級快取失效有3種方式:
- SqlSession中執行增、刪、改操作,此時sqlsession會自動清理其內部的一級快取
- 呼叫SqlSession中的clearCache方法清理其內部的一級快取
- 設定Mapper xml中select元素的flushCache屬性值為true,那么執行查詢的時候會先清空一級快取中的所有資料,然后去db中獲取資料
上面方式任何一種都會讓當前SqlSession中的以及快取失效,進而去db中獲取資料,
一級快取使用總結
- 一級快取是SqlSession級別的,每個人SqlSession有自己的一級快取,不同的SqlSession之間一級快取是相互隔離的
- mybatis中一級快取默認是自動開啟的
- 當在同一個SqlSession中執行同樣的查詢的時候,會先從一級快取中查找,如果找到了直接回傳,如果沒有找到會去訪問db,然后將db回傳的資料丟到一級快取中,下次查詢的時候直接從快取中獲取
- 一級快取清空的3種方式(1:SqlSession中執行增刪改會使一級快取失效;2:呼叫SqlSession.clearCache方法會使一級快取失效;3:Mapper xml中的select元素的flushCache屬性置為true,那么執行這個查詢會使一級快取失效)
二級快取
二級快取的使用
一級快取使用上存在局限性,必須要在同一個SqlSession中執行同樣的查詢,一級快取才能提升查詢速度,如果想在不同的SqlSession之間使用快取來加快查詢速度,此時我們需要用到二級快取了,
二級快取是mapper級別的快取,每個mapper xml有個namespace,二級快取和namespace系結的,每個namespace關聯一個二級快取,多個SqlSession可以共用二級快取,二級快取是跨SqlSession的,
二級快取默認是沒有開啟的,需要我們在mybatis全域組態檔中進行開啟:
<settings>
<!-- 開啟二級快取 -->
<setting name="cacheEnabled" value="https://www.cnblogs.com/javazhonghu/p/true"/>
</settings>
上面配置好了以后,還需要在對應的mapper xml加上下面配置,表示這個mapper中的查詢開啟二級快取:
<cache/>
配置就這么簡單,
一二級快取共存時查詢原理
一二級快取如果都開啟的情況下,資料查詢程序如下:
- 當發起一個查詢的時候,mybatis會先訪問這個namespace對應的二級快取,如果二級快取中有資料則直接回傳,否則繼續向下
- 查詢一級快取中是否有對應的資料,如果有則直接回傳,否則繼續向下
- 訪問db獲取需要的資料,然后放在當前SqlSession對應的二級快取中,并且在本地記憶體中的另外一個地方存盤一份(這個地方我們就叫TransactionalCache)
- 當SqlSession關閉的時候,也就是呼叫SqlSession的close方法的時候,此時會將TransactionalCache中的資料放到二級快取中,并且會清空當前SqlSession一級快取中的資料,
二級快取案例
mybatis全域組態檔開啟二級快取配置
<settings>
<!-- 開啟二級快取 -->
<setting name="cacheEnabled" value="https://www.cnblogs.com/javazhonghu/p/true"/>
</settings>
mapper xml中使用cache元素開啟二級快取
<!-- 啟用二級快取 -->
<cache/>
<select id="getList1" resultType="com.zhonghu.chat12.demo9.model.UserModel" parameterType="map">
SELECT id,name,age FROM user
<where>
<if test="id!=null">
AND id = #{id}
</if>
<if test="name!=null and name.toString()!=''">
AND name = #{name}
</if>
<if test="age!=null">
AND age = #{age}
</if>
</where>
</select>
測驗用例
com.zhonghu.chat12.demo9.Demo9Test#level2CacheTest1
/**
* 二級快取測驗
*
* @throws IOException
*/
@Test
public void level2CacheTest1() throws IOException {
String mybatisConfig = "demo9/mybatis-config1.xml";
this.before(mybatisConfig);
for (int i = 0; i < 2; i++) {
try (SqlSession sqlSession = this.sqlSessionFactory.openSession(true);) {
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
List<UserModel> userModelList1 = mapper.getList1(null);
log.info("{}", userModelList1);
}
}
}
上面執行了2次查詢,每次查詢都是新的SqlSession,
清慷訓者跳過二級快取的3種方式
當二級快取開啟的時候,在某個mapper xml中添加cache元素之后,這個mapper xml中所有的查詢都默認開啟了二級快取,那么我們如何清慷訓者跳過二級快取呢?3種方式如下:
- 對應的mapper中執行增刪改查會清空二級快取中資料
- select元素的flushCache屬性置為true,會先清空二級快取中的資料,然后再去db中查詢資料,然后將資料再放到二級快取中
- select元素的useCache屬性置為true,可以使這個查詢跳過二級快取,然后去查詢資料
總結
-
一二級快取訪問順序:一二級快取都存在的情況下,會先訪問二級快取,然后再訪問一級快取,最后才會訪問db,這個順序大家理解一下
-
將mapper xml中select元素的flushCache屬性置為false,最侄訓清除一級快取所有資料,同時會清除這個select所在的namespace對應的二級快取中所有的資料
-
將mapper xml中select元素的useCache置為false,會使這個查詢跳過二級快取
-
總體上來說使用快取可以提升查詢效率,這塊知識掌握了,大家可以根據業務自行選擇
最后
- 如果覺得看完有識訓,希望能關注一下,順便給我點個贊,這將會是我更新的最大動力,感謝各位的支持
- 歡迎各位關注我的公眾號【java冢狐】,專注于java和計算機基礎知識,保證讓你看完有所識訓,不信你打我
- 求一鍵三連:點贊、轉發、在看,
- 如果看完有不同的意見或者建議,歡迎多多評論一起交流,感謝各位的支持以及厚愛,
——我是冢狐,和你一樣熱愛編程,
歡迎關注公眾號“Java冢狐”獲取最新訊息
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/265029.html
標籤:Java
上一篇:Java面向物件
下一篇:Java注解學習
