關(guān)于Mybatis的幾件小事(二)

一、MyBatis緩存機(jī)制

1.簡介

  • Mybatis包含了一個(gè)非常強(qiáng)大的查詢緩存的特性卖氨,它可以非常方便地配置和定制坞淮。
  • 緩存key極大提高查詢效率
  • MyBatis系統(tǒng)中默認(rèn)定義了兩次緩存
  • 默認(rèn)情況下当纱,只有一級緩存(SqlSession級別的緩存嘀略,也稱為本地緩存)開啟。
  • 二級緩存需要手動開啟和配置乓诽,它是基于namespace級別的緩存帜羊。
  • 為了提高擴(kuò)展性,MyBatis定義了緩存接口cache鸠天∷嫌可以通過實(shí)現(xiàn)Cache接口來自定義二級緩存。

2.一級緩存

  • 一級緩存稠集,即本地緩存奶段,作用域默認(rèn)為SqlSession。當(dāng)Session flush或close后剥纷,該Session中的所有Cache將被清空痹籍。
  • 本地緩存不能被關(guān)閉,但可以調(diào)用clearCache()來清空本地緩存晦鞋,或者改變緩存的作用域蹲缠。
  • 在mybatis3.1之后棺克,可以配置本地緩存的作用域,在mybatis.xml中配置localCacheScope屬性线定。
    -MyBatis利用本地緩存防止循環(huán)引用和加速重復(fù)嵌套查詢娜谊,默認(rèn)值為SESSION,這種情況下會緩存一個(gè)會話中執(zhí)行的所有查詢斤讥。若設(shè)置值為STATEMENT纱皆,本地會話僅用在語句執(zhí)行上,對相同SqlSession的不同調(diào)用將不會共享數(shù)據(jù)芭商。
  • 同一個(gè)會話期間只要查詢過的數(shù)據(jù)都會被保存在當(dāng)前SqlSession的一個(gè)Map中
    - key:hashCode+查詢的SqlId+編寫的sql查詢語句+參數(shù)

3.一級緩存失效情況

  • 不同的SqlSession對應(yīng)不同的一級緩存
  • 同一個(gè)SqlSession但是查詢條件不同
  • 同一個(gè)SqlSession兩次執(zhí)行期間執(zhí)行了任何一次增刪改操作派草。
  • 同一個(gè)SqlSession兩次查詢期間手動清空了緩存。

4.二級緩存

  • 二級緩存蓉坎,全局作用域緩存
  • 二級緩存默認(rèn)不開腔澳眷,需要手動配置。
  • MyBatis提供二級緩存的接口以及實(shí)現(xiàn)蛉艾,緩存實(shí)現(xiàn)要求POJO實(shí)現(xiàn)Serializable接口钳踊。
  • 二級緩存在SqlSession關(guān)閉或提交之后才會生效。
  • 使用步驟:
    1. 全局配置文件中開啟二級緩存
    2. 需要使用二級緩存的映射文件處使用cache配置緩存
    3. POJO實(shí)現(xiàn)Serializable接口勿侯。

4.緩存相關(guān)屬性

  • eviction="FIFO" :緩存回收策略
    - LRU(最近最少使用):移除最長時(shí)間不被使用的對象拓瞪。
    - FIFO(先進(jìn)先出):按對象進(jìn)入緩存的順序來移除對象。
    - SOFT(軟引用):移除基于垃圾回收期狀態(tài)和軟引用規(guī)則的對象助琐。
    - WEAK(弱引用):更積極地移除基于垃圾收集器狀態(tài)和弱引用規(guī)則的對象祭埂。
    - 默認(rèn)的是LRU

  • flushInterval:刷新間隔,單位毫秒
    - 默認(rèn)情況下不設(shè)置兵钮,也就是沒有刷新間隔蛆橡,緩存僅僅調(diào)用語句時(shí)刷新。

  • size:引用數(shù)目掘譬,正整數(shù)
    - 代表緩存最多可以存儲多少個(gè)對象泰演,太大容易導(dǎo)致內(nèi)存溢出

  • readOnly:只讀,true/false
    - true:只讀緩存葱轩;會給所有調(diào)用者返回緩存對象的相同實(shí)例睦焕。這些對象不能被修改。這提供了很重要的性能優(yōu)勢靴拱。
    - false:讀寫緩存垃喊,會返回緩存對象的拷貝(通過序列化)。這會慢一些袜炕,但是安全本谜,默認(rèn)為false。

5.緩存設(shè)置

  • 全局setting的cacheEnable
    - 配置二級緩存的開關(guān)妇蛀,一級緩存一直是打開的耕突。

  • select標(biāo)簽的useCache屬性
    - 配置這個(gè)select是否使用二級緩存笤成。一級緩存一直是使用的。

  • sql標(biāo)簽的flushCache屬性:
    - 增刪改默認(rèn)為true眷茁,sql執(zhí)行后炕泳,會清空一級和二級緩存。查詢默認(rèn)false上祈。

  • sqlSession.claerCache()
    - 用來清除一級緩存

  • 當(dāng)在某一個(gè)作用域(一級緩存/二級緩存/Namespace)進(jìn)行了增刪改操作化培遵,默認(rèn)該作用域下所有select中的緩存將被clear。

6.使用第三方緩存之后的查詢流程

  1. 查詢二級緩存登刺。
  2. 如果二級緩存沒有籽腕,查詢一級緩存。
  3. 一級緩存也沒有纸俭,查詢數(shù)據(jù)庫皇耗。
image.png

二、MyBatis工作原理示意圖

image.png

三揍很、MyBatis插件開發(fā)

1.MyBatis插件

  • MyBatis在四大對象的創(chuàng)建過程中郎楼,都會有插件進(jìn)行介入,插件可以利用動態(tài)代理機(jī)制一層層的包裝目標(biāo)對象窒悔,而實(shí)現(xiàn)在目標(biāo)對象指向目標(biāo)方法之前進(jìn)行攔截的效果呜袁。
  • MyBatis允許在已映射語句執(zhí)行過程中的某一點(diǎn)進(jìn)行攔截調(diào)用。
  • 默認(rèn)情況下简珠,MyBatis允許使用插件來攔截的方法包括:
    Executor(update,query,flushStatements,commit,rollback,getTransaction,close,isClosed)
    ParameterHandler(getParameterObject,setParameters)
    ResultSetHandler(handlerResultSets,handlerOuutputParameters)
    StatementHandler(prepare,parameterize,batch,update,query)

2.插件開發(fā)步驟

  1. 編寫插件實(shí)現(xiàn)Interceptor接口阶界,并使用@Intercepts注解完成插件簽名。
@Intercepts({
    @Signature(type=StatementHandler.class,method="prepare",
              args={Connection.class})
})
public class MyPlugin implements Interceptor{}
  1. 在全局配置文件中注冊插件
<plugins>
    <plugin interceptor="com.desperado.plugin.MyPlugin">
          <property  name="username" value="tomcat"/>
     </plugin>
</plugins>

3.插件原理

  1. 按照插件注冊聲明聋庵,按照插件配置順序調(diào)用插件plugin方法膘融,生成被攔截對象的動態(tài)代理。
  2. 多個(gè)插件依次生成目標(biāo)對象的代理對象祭玉,層層包裹托启,先聲明的先包裹,形成代理鏈攘宙。
  3. 目標(biāo)想法執(zhí)行時(shí)依次從外到內(nèi)執(zhí)行intercept方法。
  4. 多個(gè)情況下拐迁,我們往往需要在某個(gè)插件中分離出來目標(biāo)對象蹭劈,可以借助MyBatis提供的SystemMateObject類來進(jìn)行獲取最后一層的h以及target屬性的值。

4.Interceptor接口

  • intercept:攔截目標(biāo)方法執(zhí)行线召。
  • plugin:生成動態(tài)代理對象铺韧,可以使用MyBatis提供的Plugin類的wrap方法。
  • setProperties:注入插件配置時(shí)設(shè)置的屬性缓淹。

5. 常用代碼

//1.分離代理對象哈打。由于會形成多次代理塔逃,所以需要通過while循環(huán)分離出最終被代理的對象,從而方便提取信息料仗。
MetaObject metaObject = SystemMetaObject.forObject(target);
while(metaObject.hasGetter("h")){
      Object h = metaObject.getValue("h");
      metaObject = SystemMetaObject.forObject(h);
}
//2.獲取到代理對象中包含的被代理的真實(shí)對象
Object obj = metaObject.getValue("target");
//3.獲取被代理對象的MetaObject方便進(jìn)行信息提取
metaObject forObject  = SystemMetaObject.forObject(obj);

四湾盗、其他操作

1.分頁操作

  • 分頁可以使用PageHelper插件。
  • 使用步驟:
    - 導(dǎo)入相關(guān)的依賴立轧,pagehelper.jar和jsqlparser.jar.
    - 在Mybatis全局配置文件中配置分頁插件
    - 使用PageHelper提供的方法進(jìn)行分頁
    - 可以使用更強(qiáng)大的PageInfo封裝返回結(jié)果格粪。

2.批量操作

  • 默認(rèn)的openSession()方法沒有參數(shù),使用它創(chuàng)建的SqlSession具有如下特性:
    - 會開啟一個(gè)事務(wù)(也就是 不自動提交)
    - 連接對象會從由活動環(huán)境配置的數(shù)據(jù)源實(shí)例得到氛改。
    - 事務(wù)隔離級別將會使用驅(qū)動或數(shù)據(jù)源的默認(rèn)設(shè)置帐萎。
    - 預(yù)處理語句不會被復(fù)用,也不會批量處理更新胜卤。

  • openSession方法的ExecutorType類型的參數(shù)疆导,枚舉類型,取值如下:
    - SIMPLE:這個(gè)執(zhí)行器類型不做特殊的事情(這是默認(rèn)裝配的)葛躏。它為每個(gè)語句的執(zhí)行創(chuàng)建一個(gè)新的預(yù)處理語句澈段。
    - REUSE:這個(gè)執(zhí)行器類型會復(fù)用預(yù)處理語句。
    - BATCH:這個(gè)執(zhí)行器會批量執(zhí)行所有更新語句紫新。

  • 批量操作就是使用MyBatis提供的BATCH類型的Executor進(jìn)行的均蜜,它的底層就是通過暫存sql的方式進(jìn)行的∶⒙剩可以保存sql到一定數(shù)量后發(fā)給數(shù)據(jù)庫執(zhí)行一次囤耳。

  • 與Spring整合中。推薦額外配置一個(gè)可以專門用來執(zhí)行批量操作的sqlSession偶芍,需要使用的時(shí)候充择,注入配置的批量操作的SqlSession,通過它獲取到mapper映射器進(jìn)行操作匪蟀。

  • 批量操作是在session.commit()以后才發(fā)送sql語句給數(shù)據(jù)庫進(jìn)行執(zhí)行的椎麦。

  • 途觀想讓其提前執(zhí)行,可以使用sqlSession.flushStatements()方法材彪,讓其執(zhí)行刷到數(shù)據(jù)庫中進(jìn)行執(zhí)行观挎。

3.存儲過程

  • 調(diào)用存儲過程
  1. select標(biāo)簽中statementType="CALLABLE".
  2. 標(biāo)簽體中調(diào)用語法
<select id="callProcedure" statementType="CALLABLE">
    call procedure_name(#{param1},#{param2})
</select>
  • mybatis對存儲過程的游標(biāo)提供了一個(gè)JdbcType=CURSOR的支持,可以智能的把游標(biāo)讀取到的數(shù)據(jù)段化,映射到我們聲明的結(jié)果集中嘁捷。

4.自定義TypeHandler處理枚舉

  • 可以通過自定義TypeHandler的形式來設(shè)置參數(shù)或者取出結(jié)果集的時(shí)候自定義參數(shù)封裝策略。
  • 步驟:
    1. 實(shí)現(xiàn)TypeHandler接口或者繼承BaseTypeHandler显熏。
    2. 使用@MappedType定義處理的Java類型雄嚣,使用@MappedJdbcTypes定義jdbcType類型。
    3. 在定義結(jié)果集標(biāo)簽或者參數(shù)處理的時(shí)候聲明使用自定義TypeHandler進(jìn)行處理或者在全局配置TypeHandler要處理的javaType
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市缓升,隨后出現(xiàn)的幾起案子鼓鲁,更是在濱河造成了極大的恐慌,老刑警劉巖港谊,帶你破解...
    沈念sama閱讀 218,755評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件骇吭,死亡現(xiàn)場離奇詭異,居然都是意外死亡封锉,警方通過查閱死者的電腦和手機(jī)绵跷,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來成福,“玉大人碾局,你說我怎么就攤上這事∨” “怎么了净当?”我有些...
    開封第一講書人閱讀 165,138評論 0 355
  • 文/不壞的土叔 我叫張陵,是天一觀的道長蕴潦。 經(jīng)常有香客問我像啼,道長,這世上最難降的妖魔是什么潭苞? 我笑而不...
    開封第一講書人閱讀 58,791評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮此疹,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘蝗碎。我一直安慰自己湖笨,他們只是感情好蹦骑,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,794評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著眠菇,像睡著了一般。 火紅的嫁衣襯著肌膚如雪捎废。 梳的紋絲不亂的頭發(fā)上放闺,一...
    開封第一講書人閱讀 51,631評論 1 305
  • 那天,我揣著相機(jī)與錄音缕坎,去河邊找鬼。 笑死篡悟,一個(gè)胖子當(dāng)著我的面吹牛谜叹,可吹牛的內(nèi)容都是我干的匾寝。 我是一名探鬼主播,決...
    沈念sama閱讀 40,362評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼荷腊,長吁一口氣:“原來是場噩夢啊……” “哼艳悔!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起女仰,我...
    開封第一講書人閱讀 39,264評論 0 276
  • 序言:老撾萬榮一對情侶失蹤猜年,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后疾忍,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體乔外,經(jīng)...
    沈念sama閱讀 45,724評論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年一罩,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了杨幼。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,040評論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡聂渊,死狀恐怖差购,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情汉嗽,我是刑警寧澤欲逃,帶...
    沈念sama閱讀 35,742評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站饼暑,受9級特大地震影響稳析,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜撵孤,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,364評論 3 330
  • 文/蒙蒙 一迈着、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧邪码,春花似錦裕菠、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至影钉,卻和暖如春画髓,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背平委。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評論 1 270
  • 我被黑心中介騙來泰國打工奈虾, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,247評論 3 371
  • 正文 我出身青樓匾鸥,卻偏偏與公主長得像碉纳,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子劳曹,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,979評論 2 355

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