Mybatis 詳解--- 一級緩存、二級緩存

2019獨角獸企業重金招聘Python工程師標準>>> hot3.png

Mybatis 為我們提供了一級緩存和二級緩存,可以通過下圖來理解:

3mimam6.png!web

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

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

1、一級緩存

①、我們在一個 sqlSession 中,對 User 表根據id進行兩次查詢,查看他們發出sql語句的情況。

@Test
public void testSelectOrderAndUserByOrderId(){//根據 sqlSessionFactory 產生 sessionSqlSession sqlSession = sessionFactory.openSession();String statement = "one.to.one.mapper.OrdersMapper.selectOrderAndUserByOrderID";UserMapper userMapper = sqlSession.getMapper(UserMapper.class);//第一次查詢,發出sql語句,并將查詢的結果放入緩存中User u1 = userMapper.selectUserByUserId(1);System.out.println(u1);//第二次查詢,由于是同一個sqlSession,會在緩存中查找查詢結果//如果有,則直接從緩存中取出來,不和數據庫進行交互User u2 = userMapper.selectUserByUserId(1);System.out.println(u2);sqlSession.close();
}

查看控制臺打印情況:

VZzUNzz.png!web

②、?同樣是對user表進行兩次查詢,只不過兩次查詢之間進行了一次update操作。

@Test
public void testSelectOrderAndUserByOrderId(){//根據 sqlSessionFactory 產生 sessionSqlSession sqlSession = sessionFactory.openSession();String statement = "one.to.one.mapper.OrdersMapper.selectOrderAndUserByOrderID";UserMapper userMapper = sqlSession.getMapper(UserMapper.class);//第一次查詢,發出sql語句,并將查詢的結果放入緩存中User u1 = userMapper.selectUserByUserId(1);System.out.println(u1);//第二步進行了一次更新操作,sqlSession.commit()u1.setSex("女");userMapper.updateUserByUserId(u1);sqlSession.commit();//第二次查詢,由于是同一個sqlSession.commit(),會清空緩存信息//則此次查詢也會發出 sql 語句User u2 = userMapper.selectUserByUserId(1);System.out.println(u2);sqlSession.close();
}

控制臺打印情況:

MzINRnr.png!web

③、總結

1、第一次發起查詢用戶id為1的用戶信息,先去找緩存中是否有id為1的用戶信息,如果沒有,從數據庫查詢用戶信息。得到用戶信息,將用戶信息存儲到一級緩存中。

2、如果中間sqlSession去執行commit操作(執行插入、更新、刪除),則會清空SqlSession中的一級緩存,這樣做的目的為了讓緩存中存儲的是最新的信息,避免臟讀。

3、第二次發起查詢用戶id為1的用戶信息,先去找緩存中是否有id為1的用戶信息,緩存中有,直接從緩存中獲取用戶信息。

YnI7z2q.png!web

2、二級緩存

二級緩存的原理和一級緩存原理一樣,第一次查詢,會將數據放入緩存中,然后第二次查詢則會直接去緩存中取。但是一級緩存是基于 sqlSession 的,而 二級緩存是基于 mapper文件的namespace的,也就是說多個sqlSession可以共享一個mapper中的二級緩存區域,并且如果兩個mapper的namespace相同,即使是兩個mapper,那么這兩個mapper中執行sql查詢到的數據也將存在相同的二級緩存區域中。

yayMFby.png!web

那么二級緩存是如何使用的呢?

①、開啟二級緩存

和一級緩存默認開啟不一樣,二級緩存需要我們手動開啟

首先在全局配置文件 mybatis-configuration.xml 文件中加入如下代碼:

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

其次在 UserMapper.xml 文件中開啟緩存

<!-- 開啟二級緩存 -->
<cache></cache>

我們可以看到 mapper.xml 文件中就這么一個空標簽<cache/>,其實這里可以配置<cache type="org.apache.ibatis.cache.impl.PerpetualCache"/>,PerpetualCache這個類是mybatis默認實現緩存功能的類。我們不寫type就使用mybatis默認的緩存,也可以去實現 Cache 接口來自定義緩存。

vENfYvN.png!web

ri2uIjB.png!web

我們可以看到 二級緩存 底層還是 HashMap 架構。

②、po 類實現??Serializable??序列化接口

U7NFbmm.png!web

開啟了二級緩存后,還需要將要緩存的pojo實現Serializable接口,為了將緩存數據取出執行反序列化操作,因為二級緩存數據存儲介質多種多樣,不一定只存在內存中,有可能存在硬盤中,如果我們要再取這個緩存的話,就需要反序列化了。所以mybatis中的pojo都去實現Serializable接口。

③、測試

一、測試二級緩存和sqlSession 無關

@Test
public void testTwoCache(){//根據 sqlSessionFactory 產生 sessionSqlSession sqlSession1 = sessionFactory.openSession();SqlSession sqlSession2 = sessionFactory.openSession();String statement = "com.ys.twocache.UserMapper.selectUserByUserId";UserMapper userMapper1 = sqlSession1.getMapper(UserMapper.class);UserMapper userMapper2 = sqlSession2.getMapper(UserMapper.class);//第一次查詢,發出sql語句,并將查詢的結果放入緩存中User u1 = userMapper1.selectUserByUserId(1);System.out.println(u1);sqlSession1.close();//第一次查詢完后關閉sqlSession//第二次查詢,即使sqlSession1已經關閉了,這次查詢依然不發出sql語句User u2 = userMapper2.selectUserByUserId(1);System.out.println(u2);sqlSession2.close();
}

可以看出上面兩個不同的sqlSession,第一個關閉了,第二次查詢依然不發出sql查詢語句。

二、測試執行 commit() 操作,二級緩存數據清空

@Test
public void testTwoCache(){//根據 sqlSessionFactory 產生 sessionSqlSession sqlSession1 = sessionFactory.openSession();SqlSession sqlSession2 = sessionFactory.openSession();SqlSession sqlSession3 = sessionFactory.openSession();String statement = "com.ys.twocache.UserMapper.selectUserByUserId";UserMapper userMapper1 = sqlSession1.getMapper(UserMapper.class);UserMapper userMapper2 = sqlSession2.getMapper(UserMapper.class);UserMapper userMapper3 = sqlSession2.getMapper(UserMapper.class);//第一次查詢,發出sql語句,并將查詢的結果放入緩存中User u1 = userMapper1.selectUserByUserId(1);System.out.println(u1);sqlSession1.close();//第一次查詢完后關閉sqlSession//執行更新操作,commit()u1.setUsername("aaa");userMapper3.updateUserByUserId(u1);sqlSession3.commit();//第二次查詢,由于上次更新操作,緩存數據已經清空(防止數據臟讀),這里必須再次發出sql語句User u2 = userMapper2.selectUserByUserId(1);System.out.println(u2);sqlSession2.close();
}

查看控制臺情況:

BVJZbm6.png!web

④、useCache和flushCache

mybatis中還可以配置userCache和flushCache等配置項,userCache是用來設置是否禁用二級緩存的,在statement中設置useCache=false可以禁用當前select語句的二級緩存,即每次查詢都會發出sql去查詢,默認情況是true,即該sql使用二級緩存。

<select id="selectUserByUserId" useCache="false" resultType="com.ys.twocache.User" parameterType="int">select * from user where id=#{id}
</select>

這種情況是針對每次查詢都需要最新的數據sql,要設置成useCache=false,禁用二級緩存,直接從數據庫中獲取。

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

設置statement配置中的flushCache=”true” 屬性,默認情況下為true,即刷新緩存,如果改成false則不會刷新。使用緩存時如果手動修改數據庫表中的查詢數據會出現臟讀。

<select id="selectUserByUserId" flushCache="true" useCache="false" resultType="com.ys.twocache.User" parameterType="int">select * from user where id=#{id}
</select>

一般下執行完commit操作都需要刷新緩存,flushCache=true表示刷新緩存,這樣可以避免數據庫臟讀。所以我們不用設置,默認即可。

歡迎工作一到五年的Java工程師朋友們加入Java高級交流:698581634。群內提供免費的Java架構學習資料(Spring,MyBatis,Netty源碼分析,高并發、高性能、分布式、微服務架構的原理,JVM性能優化等...)這些成為架構師必備的知識體系。
合理利用自己每一分每一秒的時間來學習提升自己,不要再用"沒有時間“來掩飾自己思想上的懶惰!趁年輕,使勁拼,給未來的自己一個交代!

轉載于:https://my.oschina.net/u/3967312/blog/2050464

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/450712.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/450712.shtml
英文地址,請注明出處:http://en.pswp.cn/news/450712.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

我的nabcd

我們組要做的軟件是一款MP3播放軟件&#xff0c;名字叫TDG音樂 N&#xff08;need需求&#xff09;&#xff0c;由于現在版權越來越被重視&#xff0c;許多播放軟件里面的大部分歌曲都是收費的&#xff0c;不想花錢又想聽可怎么辦呢&#xff0c;只能在網上找免費資源&#xff0…

【C/C++和指針】深度解析---指針與數組 【精華】

一&#xff0c;引例子 二維數組可以使用指向數組的指針代替&#xff0c;而指針數組才可以用指向指針的指針代替。 [html] view plaincopy#include<iostream> using namespace std; void main() { char *a[]{"Hello","the","World&q…

Redis常見面試題詳解

文章目錄1. Redis1.1 Redis可以用來做什么&#xff1f;1.2 Redis和傳統的關系型數據庫有什么不同&#xff1f;1.3 Redis有哪些數據類型&#xff1f;1.4 Redis是單線程的&#xff0c;為什么還能這么快&#xff1f;1.5 Redis在持久化時fork出一個子進程&#xff0c;這時已經有兩個…

IntelliJ 創建main函數、for循環、輸出語句快捷鍵

前些天發現了一個巨牛的人工智能學習網站&#xff0c;通俗易懂&#xff0c;風趣幽默&#xff0c;忍不住分享一下給大家。點擊跳轉到教程。 今天偶然發現了IntelliJ中 創建main函數的快捷鍵&#xff0c;依次還有for循環&#xff0c;System.out.println(); 在編寫代碼的時候直接…

CentOS新增用戶并授予sudo權限

2019獨角獸企業重金招聘Python工程師標準>>> 新增用戶 添加用戶useradd demo設置用戶密碼passwd demo授予sudo權限 輸入以下命令&#xff0c;編輯sudoers配置&#xff1a;visudo找到以下行root ALL(ALL) ALL增加以下內容&#xff1a;demo ALL(ALL) ALL保存后登錄dem…

跨站腳本功攻擊,xss,一個簡單的例子讓你知道什么是xss攻擊

跨站腳本功攻擊&#xff0c;xss&#xff0c;一個簡單的例子讓你知道什么是xss攻擊 一、總結 一句話總結&#xff1a;比如用戶留言功能&#xff0c;用戶留言中寫的是網頁可執行代碼&#xff0c;例如js代碼&#xff0c;然后這段代碼在可看到這段留言的不同一戶的顯示上就會執行。…

用業績建立信任

當年從香港到美國&#xff0c;對于中學畢業的郭尊華來說&#xff0c;算是一個失敗。他盡管家境普通&#xff0c;但因為成績不佳進不了香港的大學&#xff0c;不得不遠赴美國讀書。在課余做過挖地、當侍者等多份工作的他&#xff0c;在大三的時候終于得到一份初級工程師的工作。…

idea 快捷鍵 小結

前些天發現了一個巨牛的人工智能學習網站&#xff0c;通俗易懂&#xff0c;風趣幽默&#xff0c;忍不住分享一下給大家。點擊跳轉到教程。1.setting 打開快捷鍵&#xff1a;ctrl alt s 在 file - setting 中。 2.回到默認設置&#xff1a;刪除如下路徑的文件夾 C:\Users…

Jenkins常用插件

Generic Webhook Trigger Plugin觸發器webhook用戶觸發構建Deploy to container Plugin部署到tomcatGradle Plugin Gradle插件構建項目Maven Plugin Maven插件構建項目Git Plugin Git插件克隆項目GitHub plugin GitHub插件集成githubSSH Slaves plugin SSH插件用于遠程登錄Buil…

spark廣播變量 和 累加器

1 為什么使用廣播變量 和 累加器 變量存在的問題&#xff1a;在spark程序中&#xff0c;當一個傳遞給Spark操作(例如map和reduce)的函數在遠程節點上面運行時&#xff0c;Spark操作實際上操作的是這個函數所用變量的一個獨立副本。這些變量會被復制到每臺機器上&#xff0c;并且…

分布式常見面試題詳解

文章目錄1. 分布式1.1 什么是CAP原則&#xff1f;1.2 說一說你對高并發的理解1.3 如何實現分布式存儲&#xff1f;1.4 說一說你對分布式事務的了解1.5 分布式系統如何保證最終一致性&#xff1f;1.6 談談你對分布式的單點問題的了解1.7 HTTP和RPC有什么區別&#xff1f;1.7 HTT…

C11標準委員會成員解讀C語言新標準

導讀&#xff1a;C語言國際標準新的新草案之前已經公布&#xff0c;新標準提高了對C的兼容性&#xff0c;并將新的特性增加到C語言中。此外支持多線程的功能也受到了開發者的關注&#xff0c;基于ISO/IEC TR 19769:2004規范下支持Unicode&#xff0c;提供更多用于查詢浮點數類型…

如何將拷貝過來的數據 *.ibd 文件生效

1.將拷貝的數據文件 "qqq.idb"放在自己的數據庫中. 一般存放在 mysql/ data/ databasename 下 2. "qqq.idb" 改個名字-->"qqq--.idb", 主要是避免沖突&#xff01; 3.執行 create table qqq(...) 語句&#xff0c;此時除了會生成一個 qqq…

windows 下啟動zookeeper的zkServer.cmd服務閃退

前些天發現了一個巨牛的人工智能學習網站&#xff0c;通俗易懂&#xff0c;風趣幽默&#xff0c;忍不住分享一下給大家。點擊跳轉到教程。 解決方案把conf目錄下的默認zoo_sample.cfg的文件名字改成zoo.cfg 即可&#xff1a; 以上轉自&#xff1a;http://blog.csdn.net/qq4960…

設計模式常見面試真題詳解

文章目錄1. 設計模式1.1 說一說設計模式的六大原則1.2 說一下六大原則中的開閉原則1.3 手寫一個單例模式1.4 手寫一個線程安全的單例模式1.5 說一說你對工廠模式的理解1.6 簡單工廠模式和抽象工廠模式有什么區別&#xff1f;1.7 如何實現工廠模式&#xff1f;1.8 說一說你策略模…

Android內存優化之內存泄漏

內存泄漏 內存泄漏一般有以下幾種情況&#xff1a;單例、靜態變量、Handler、匿名內部類、資源使用未關閉 單例導致的內存泄漏 單例的情況主要是因為單例的生命周期比較長&#xff0c;如果引用的一些資源&#xff08;比如Context、圖片等&#xff09;沒有做特殊處理&#xff0c…

cmd - 使用curl命令的注意點

前言 最近在cmd中使用curl命令來測試rest api&#xff0c;發現有不少問題&#xff0c;這里記錄一下。 在cmd中使用curl命令的注意事項 json不能由單引號包括起來json數據里的雙引號要用反斜杠\轉義json數據里不能帶有空格如果想要在json數據里使用空格則必須用雙引號將整個json…

指針常見定義

再給出常用的C變量的定義方式&#xff1a;a) 一個整型數&#xff08;An integer&#xff09; b) 一個指向整型數的指針&#xff08;A pointer to an integer&#xff09; c) 一個指向指針的的指針&#xff0c;它指向的指針是指向一個整型數&#xff08;A pointer to a pointer …

場景應用題目常見面試真題詳解

文章目錄1. 場景應用1.1 微信紅包相關問題1.2 秒殺系統相關問題1.3 掃碼登錄流程1.4 如何實現單點登錄&#xff1f;1.5 如何設計一個本地緩存&#xff1f;1. 場景應用 1.1 微信紅包相關問題 參考答案 概況&#xff1a;2014年微信紅包使用數據庫硬抗整個流量&#xff0c;2015…

后Kubernetes時代的微服務

\本文要點\\當前微服務架構依然是最流行的分布式系統架構風格。Kubernetes和云原生運動已大規模地重新定義了應用設計和開發中的一些方面。\\t在云原生平臺上&#xff0c;服務僅具備可觀測性是不夠的。更基本的先決條件是使用檢查健康、響應信號、聲明資源消耗等手段實現微服務…