MyBatis從入門到入土——緩存的使用

這是mybatis系列第11篇浴滴。沒看前文的建議先去【Java冢狐】公眾號(hào)中查看前文瘸洛,方便理解和掌握守伸。

什么是緩存斤吐?

緩存就是存儲(chǔ)數(shù)據(jù)的一個(gè)地方(稱作:Cache)站粟,當(dāng)程序要讀取數(shù)據(jù)時(shí)黍图,會(huì)首先從緩存中獲取,有則直接返回奴烙,否則從其他存儲(chǔ)設(shè)備中獲取雌隅,緩存最重要的一點(diǎn)就是從其內(nèi)部獲取數(shù)據(jù)的速度是非常快的缸沃,通過緩存可以加快數(shù)據(jù)的訪問速度恰起。比如我們從db中獲取數(shù)據(jù),中間需要經(jīng)過網(wǎng)絡(luò)傳輸耗時(shí)趾牧,db server從磁盤讀取數(shù)據(jù)耗時(shí)等检盼,如果這些數(shù)據(jù)直接放在jvm對(duì)應(yīng)的內(nèi)存中,訪問是不是會(huì)快很多翘单。

mybatis中的緩存

mybatis中分為一級(jí)緩存和二級(jí)緩存吨枉。

  • 一級(jí)緩存是SqlSession級(jí)別的緩存,在操作數(shù)據(jù)庫(kù)時(shí)需要構(gòu)造 sqlSession對(duì)象哄芜,在對(duì)象中有一個(gè)數(shù)據(jù)結(jié)構(gòu)(HashMap)用于存儲(chǔ)緩存數(shù)據(jù)貌亭,不同的sqlSession之間的緩存數(shù)據(jù)區(qū)域(HashMap)是互相不影響的。
  • 二級(jí)緩存是mapper級(jí)別的緩存认臊,多個(gè)SqlSession去操作同一個(gè)Mapper的sql語(yǔ)句圃庭,多個(gè)SqlSession可以共用二級(jí)緩存,二級(jí)緩存是跨SqlSession的失晴。

一級(jí)緩存

一級(jí)緩存是SqlSession級(jí)別的緩存剧腻,每個(gè)SqlSession都有自己?jiǎn)为?dú)的一級(jí)緩存,多個(gè)SqlSession之間的一級(jí)緩存是相互隔離的涂屁,互不影響书在,mybatis中一級(jí)緩存是默認(rèn)自動(dòng)開啟的。

一級(jí)緩存工作原理:在同一個(gè)SqlSession中去多次去執(zhí)行同樣的查詢拆又,每次執(zhí)行的時(shí)候會(huì)先到一級(jí)緩存中查找儒旬,如果緩存中有就直接返回栏账,如果一級(jí)緩存中沒有相關(guān)數(shù)據(jù),mybatis就會(huì)去db中進(jìn)行查找栈源,然后將查找到的數(shù)據(jù)放入一級(jí)緩存中发笔,第二次執(zhí)行同樣的查詢的時(shí)候,會(huì)發(fā)現(xiàn)緩存中已經(jīng)存在了凉翻,會(huì)直接返回了讨。一級(jí)緩存的存儲(chǔ)介質(zhì)是內(nèi)存,是用一個(gè)HashMap來(lái)存儲(chǔ)數(shù)據(jù)的制轰,所以訪問速度是非城凹疲快的。

一級(jí)緩存案例

案例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);
下面是查詢用戶信息垃杖,返回一個(gè)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>
對(duì)應(yīng)的mapper接口方法
List<UserModel> getList1(Map<String, Object> paramMap);
測(cè)試用例
com.zhonghu.chat12.demo9.Demo9Test#level1CacheTest1
/**
 * 一級(jí)緩存測(cè)試
 *
 * @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);
    }
}

上面的代碼在同一個(gè)SqlSession中去執(zhí)行了2次獲取用戶列表信息男杈,2次查詢結(jié)果分別放在userModelList1和userModelList2,最終代碼中也會(huì)判斷這兩個(gè)集合是否相等调俘,下面我們運(yùn)行一下看看會(huì)訪問幾次db伶棒。

運(yùn)行輸出
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只輸出了一次彩库,說明第一次會(huì)訪問數(shù)據(jù)庫(kù)肤无,第二次直接從緩存中獲取的,最后輸出了一個(gè)true骇钦,也說明兩次返回結(jié)果是同一個(gè)對(duì)象宛渐,第二次直接從緩存中獲取數(shù)據(jù)的,加快了查詢的速度眯搭。

清空一級(jí)緩存的3種方式

同一個(gè)SqlSession中查詢同樣的數(shù)據(jù)窥翩,mybatis默認(rèn)會(huì)從一級(jí)緩存中獲取,如果緩存中沒有鳞仙,才會(huì)訪問db寇蚊,那么如果我們希望不走緩存而是直接去訪問數(shù)據(jù)庫(kù),又該如何操作呢棍好?

讓一級(jí)緩存失效有3種方式:

  • SqlSession中執(zhí)行增仗岸、刪、改操作梳玫,此時(shí)sqlsession會(huì)自動(dòng)清理其內(nèi)部的一級(jí)緩存
  • 調(diào)用SqlSession中的clearCache方法清理其內(nèi)部的一級(jí)緩存
  • 設(shè)置Mapper xml中select元素的flushCache屬性值為true爹梁,那么執(zhí)行查詢的時(shí)候會(huì)先清空一級(jí)緩存中的所有數(shù)據(jù),然后去db中獲取數(shù)據(jù)

上面方式任何一種都會(huì)讓當(dāng)前SqlSession中的以及緩存失效提澎,進(jìn)而去db中獲取數(shù)據(jù)。

一級(jí)緩存使用總結(jié)

  • 一級(jí)緩存是SqlSession級(jí)別的念链,每個(gè)人SqlSession有自己的一級(jí)緩存盼忌,不同的SqlSession之間一級(jí)緩存是相互隔離的
  • mybatis中一級(jí)緩存默認(rèn)是自動(dòng)開啟的
  • 當(dāng)在同一個(gè)SqlSession中執(zhí)行同樣的查詢的時(shí)候积糯,會(huì)先從一級(jí)緩存中查找,如果找到了直接返回谦纱,如果沒有找到會(huì)去訪問db看成,然后將db返回的數(shù)據(jù)丟到一級(jí)緩存中,下次查詢的時(shí)候直接從緩存中獲取
  • 一級(jí)緩存清空的3種方式(1:SqlSession中執(zhí)行增刪改會(huì)使一級(jí)緩存失效跨嘉;2:調(diào)用SqlSession.clearCache方法會(huì)使一級(jí)緩存失效川慌;3:Mapper xml中的select元素的flushCache屬性置為true,那么執(zhí)行這個(gè)查詢會(huì)使一級(jí)緩存失效)

二級(jí)緩存

二級(jí)緩存的使用

一級(jí)緩存使用上存在局限性祠乃,必須要在同一個(gè)SqlSession中執(zhí)行同樣的查詢梦重,一級(jí)緩存才能提升查詢速度,如果想在不同的SqlSession之間使用緩存來(lái)加快查詢速度亮瓷,此時(shí)我們需要用到二級(jí)緩存了琴拧。

二級(jí)緩存是mapper級(jí)別的緩存,每個(gè)mapper xml有個(gè)namespace嘱支,二級(jí)緩存和namespace綁定的蚓胸,每個(gè)namespace關(guān)聯(lián)一個(gè)二級(jí)緩存,多個(gè)SqlSession可以共用二級(jí)緩存除师,二級(jí)緩存是跨SqlSession的沛膳。

二級(jí)緩存默認(rèn)是沒有開啟的,需要我們?cè)趍ybatis全局配置文件中進(jìn)行開啟:

<settings>
    <!-- 開啟二級(jí)緩存 -->
    <setting name="cacheEnabled" value="true"/>
</settings>

上面配置好了以后汛聚,還需要在對(duì)應(yīng)的mapper xml加上下面配置于置,表示這個(gè)mapper中的查詢開啟二級(jí)緩存:

<cache/>

配置就這么簡(jiǎn)單。

一二級(jí)緩存共存時(shí)查詢?cè)?/h4>

一二級(jí)緩存如果都開啟的情況下贞岭,數(shù)據(jù)查詢過程如下:

  • 當(dāng)發(fā)起一個(gè)查詢的時(shí)候八毯,mybatis會(huì)先訪問這個(gè)namespace對(duì)應(yīng)的二級(jí)緩存,如果二級(jí)緩存中有數(shù)據(jù)則直接返回瞄桨,否則繼續(xù)向下
  • 查詢一級(jí)緩存中是否有對(duì)應(yīng)的數(shù)據(jù)话速,如果有則直接返回,否則繼續(xù)向下
  • 訪問db獲取需要的數(shù)據(jù)芯侥,然后放在當(dāng)前SqlSession對(duì)應(yīng)的二級(jí)緩存中泊交,并且在本地內(nèi)存中的另外一個(gè)地方存儲(chǔ)一份(這個(gè)地方我們就叫TransactionalCache)
  • 當(dāng)SqlSession關(guān)閉的時(shí)候,也就是調(diào)用SqlSession的close方法的時(shí)候柱查,此時(shí)會(huì)將TransactionalCache中的數(shù)據(jù)放到二級(jí)緩存中廓俭,并且會(huì)清空當(dāng)前SqlSession一級(jí)緩存中的數(shù)據(jù)。

二級(jí)緩存案例

mybatis全局配置文件開啟二級(jí)緩存配置
<settings>
    <!-- 開啟二級(jí)緩存 -->
    <setting name="cacheEnabled" value="true"/>
</settings>
mapper xml中使用cache元素開啟二級(jí)緩存
<!-- 啟用二級(jí)緩存 -->
<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>
測(cè)試用例
com.zhonghu.chat12.demo9.Demo9Test#level2CacheTest1
/**
 * 二級(jí)緩存測(cè)試
 *
 * @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);
        }
    }
}

上面執(zhí)行了2次查詢唉工,每次查詢都是新的SqlSession研乒。

清空或者跳過二級(jí)緩存的3種方式

當(dāng)二級(jí)緩存開啟的時(shí)候,在某個(gè)mapper xml中添加cache元素之后淋硝,這個(gè)mapper xml中所有的查詢都默認(rèn)開啟了二級(jí)緩存雹熬,那么我們?nèi)绾吻蹇栈蛘咛^二級(jí)緩存呢宽菜?3種方式如下:

  • 對(duì)應(yīng)的mapper中執(zhí)行增刪改查會(huì)清空二級(jí)緩存中數(shù)據(jù)
  • select元素的flushCache屬性置為true,會(huì)先清空二級(jí)緩存中的數(shù)據(jù)竿报,然后再去db中查詢數(shù)據(jù)铅乡,然后將數(shù)據(jù)再放到二級(jí)緩存中
  • select元素的useCache屬性置為true,可以使這個(gè)查詢跳過二級(jí)緩存烈菌,然后去查詢數(shù)據(jù)

總結(jié)

  • 一二級(jí)緩存訪問順序:一二級(jí)緩存都存在的情況下阵幸,會(huì)先訪問二級(jí)緩存,然后再訪問一級(jí)緩存芽世,最后才會(huì)訪問db挚赊,這個(gè)順序大家理解一下

  • 將mapper xml中select元素的flushCache屬性置為false,最終會(huì)清除一級(jí)緩存所有數(shù)據(jù)捂襟,同時(shí)會(huì)清除這個(gè)select所在的namespace對(duì)應(yīng)的二級(jí)緩存中所有的數(shù)據(jù)

  • 將mapper xml中select元素的useCache置為false咬腕,會(huì)使這個(gè)查詢跳過二級(jí)緩存

  • 總體上來(lái)說使用緩存可以提升查詢效率,這塊知識(shí)掌握了葬荷,大家可以根據(jù)業(yè)務(wù)自行選擇

    最后

    • 如果覺得看完有收獲涨共,希望能關(guān)注一下,順便給我點(diǎn)個(gè)贊宠漩,這將會(huì)是我更新的最大動(dòng)力举反,感謝各位的支持
    • 歡迎各位關(guān)注我的公眾號(hào)【java冢狐】,專注于java和計(jì)算機(jī)基礎(chǔ)知識(shí)扒吁,保證讓你看完有所收獲火鼻,不信你打我
    • 求一鍵三連:點(diǎn)贊、轉(zhuǎn)發(fā)雕崩、在看魁索。
    • 如果看完有不同的意見或者建議,歡迎多多評(píng)論一起交流盼铁。感謝各位的支持以及厚愛粗蔚。

    ——我是冢狐,和你一樣熱愛編程饶火。

歡迎關(guān)注公眾號(hào)“ Java冢狐”鹏控,獲取最新消息

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市肤寝,隨后出現(xiàn)的幾起案子当辐,更是在濱河造成了極大的恐慌,老刑警劉巖鲤看,帶你破解...
    沈念sama閱讀 217,509評(píng)論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件缘揪,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)寺晌,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,806評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門世吨,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)澡刹,“玉大人呻征,你說我怎么就攤上這事“战剑” “怎么了陆赋?”我有些...
    開封第一講書人閱讀 163,875評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)嚷闭。 經(jīng)常有香客問我攒岛,道長(zhǎng),這世上最難降的妖魔是什么胞锰? 我笑而不...
    開封第一講書人閱讀 58,441評(píng)論 1 293
  • 正文 為了忘掉前任灾锯,我火速辦了婚禮,結(jié)果婚禮上嗅榕,老公的妹妹穿的比我還像新娘顺饮。我一直安慰自己,他們只是感情好凌那,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,488評(píng)論 6 392
  • 文/花漫 我一把揭開白布兼雄。 她就那樣靜靜地躺著,像睡著了一般帽蝶。 火紅的嫁衣襯著肌膚如雪赦肋。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,365評(píng)論 1 302
  • 那天励稳,我揣著相機(jī)與錄音佃乘,去河邊找鬼。 笑死驹尼,一個(gè)胖子當(dāng)著我的面吹牛趣避,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播扶欣,決...
    沈念sama閱讀 40,190評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼鹅巍,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了料祠?” 一聲冷哼從身側(cè)響起骆捧,我...
    開封第一講書人閱讀 39,062評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎髓绽,沒想到半個(gè)月后敛苇,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,500評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,706評(píng)論 3 335
  • 正文 我和宋清朗相戀三年枫攀,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了括饶。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,834評(píng)論 1 347
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡来涨,死狀恐怖图焰,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情蹦掐,我是刑警寧澤技羔,帶...
    沈念sama閱讀 35,559評(píng)論 5 345
  • 正文 年R本政府宣布,位于F島的核電站卧抗,受9級(jí)特大地震影響藤滥,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜社裆,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,167評(píng)論 3 328
  • 文/蒙蒙 一拙绊、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧泳秀,春花似錦标沪、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,779評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至磺陡,卻和暖如春趴梢,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背币他。 一陣腳步聲響...
    開封第一講書人閱讀 32,912評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工坞靶, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人蝴悉。 一個(gè)月前我還...
    沈念sama閱讀 47,958評(píng)論 2 370
  • 正文 我出身青樓彰阴,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親拍冠。 傳聞我的和親對(duì)象是個(gè)殘疾皇子尿这,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,779評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容

  • 前面的內(nèi)容我們討論了映射文件里面幾乎所有的標(biāo)簽和用法,下面我來(lái)討論最后一個(gè)庆杜,也就是緩存的用法射众。 一級(jí)緩存 Myba...
    郭藝賓閱讀 202評(píng)論 0 0
  • 前言 主題是Mybatis一級(jí)和二級(jí)緩存的應(yīng)用及源碼分析。希望在本場(chǎng)chat結(jié)束后晃财,能夠幫助讀者朋友明白以下三點(diǎn)叨橱。...
    余平的余_余平的平閱讀 1,327評(píng)論 0 12
  • 1 Mybatis入門 1.1 單獨(dú)使用jdbc編程問題總結(jié) 1.1.1 jdbc程序 上邊使...
    哇哈哈E閱讀 3,306評(píng)論 0 38
  • 緩存的定義 緩存一般是orm框架會(huì)提供的功能,目的是提升查詢效率和減少數(shù)據(jù)庫(kù)的壓力。Mybatis有1級(jí)緩存和2級(jí)...
    我是許仙閱讀 500評(píng)論 0 1
  • 推薦指數(shù): 6.0 書籍主旨關(guān)鍵詞:特權(quán)罗洗、焦點(diǎn)愉舔、注意力、語(yǔ)言聯(lián)想伙菜、情景聯(lián)想 觀點(diǎn): 1.統(tǒng)計(jì)學(xué)現(xiàn)在叫數(shù)據(jù)分析轩缤,社會(huì)...
    Jenaral閱讀 5,721評(píng)論 0 5