繼上一篇博客,咱們講述了mybatis的一級緩存,接下來,咱們來學習一下mybatis的二級緩存html
博客連接地址: http://blog.csdn.NET/liweizhong193516/article/details/53639350 java
按照慣例,先來一張形象一點的圖:mysql
二級緩存區域是根據mapper的namespace劃分的,相同namespace的mapper查詢數據放在同一個區域,若是使用mapper代理方法每一個mapper的namespace都不一樣,此時能夠理解爲二級緩存區域是根據mapper劃分,也就是根據命名空間來劃分的,若是兩個mapper文件的命名空間同樣,那樣,他們就能夠共享一個mapper緩存。web
每次查詢會先從緩存區域找,若是找不到從數據庫查詢,查詢到數據將數據寫入緩存。sql
Mybatis內部存儲緩存使用一個HashMap,key爲hashCode+sqlId+Sql語句。value爲從查詢出來映射生成的Java對象數據庫
sqlSession執行insert、update、delete等操做commit提交後會清空緩存區域。緩存
開啓緩存:
在這特別提醒一下,Mybatis的二級緩存是須要配置來開啓的,咱們須要在Mybatis的核心配置文件SqlMapConfig.xml中加入:安全
![]()
而後還要在Mapper映射文件中添加一行:session
假如說,已開啓二級緩存的Mapper中有個statement要求禁用怎麼辦,那也不難,只須要在statement中設置useCache=false就能夠禁用當前select語句的二級緩存,也就是每次都會生成sql去查詢,ps:默認狀況下默認是true,也就是默認使用二級緩存
刷新緩存:
在mapper的同一個namespace中,若是有其餘insert、update、delete操做後都須要執行刷新緩存操做,來避免髒讀。這時咱們只須要設置statement配置中的flushCache=「true「屬性,就會默認刷新緩存,相反若是是false就不會了。固然,無論開不開緩存刷新功能,你要是手動更改數據庫表,那都確定不能避免髒讀的發生,那就屬於手賤了。mybatis
那既然可以刷新緩存,能定時刷新嗎?也就是設置時間間隔來刷新緩存,答案是確定的。咱們在mapper映射文件中添加<cache/>來表示開啓緩存,那接下來,只須要咱們在配置flushinterval(刷新間隔)就哦了: flushInterval(刷新間隔)能夠被設置爲任意的正整數,並且它們表明一個合理的毫秒形式的時間段。默認狀況是不設置,也就是沒有刷新間隔,緩存僅僅調用語句時刷新。 size(引用數目)能夠被設置爲任意正整數,要記住你緩存的對象數目和你運行環境的可用內存資源數目。默認值是1024。 readOnly(只讀)屬性能夠被設置爲true或false。只讀的緩存會給全部調用者返回緩存對象的相同實例。所以這些對象不能被修改。這提供了很重要的性能優點。可讀寫的緩存會返回緩存對象的拷貝(經過序列化)。這會慢一些,可是安全,所以默認是false。
而這個例子更高級的配置建立了一個 FIFO 緩存,並每隔 60 秒刷新,存數結果對象或列表的 512 個引用,並且返回的對象被認爲是隻讀的,所以在不一樣線程中的調用者之間修改它們會致使衝突。可用的收回策略有, 默認的是 LRU:
1. LRU – 最近最少使用的:移除最長時間不被使用的對象。
2. FIFO – 先進先出:按對象進入緩存的順序來移除它們。
3. SOFT – 軟引用:移除基於垃圾回收器狀態和軟引用規則的對象。
4. WEAK – 弱引用:更積極地移除基於垃圾收集器狀態和弱引用規則的對象。
這就是咱們軟考擅長的東西了,不用解釋了吧!
說了這麼多,擺個例子來結束本篇博文:
運行效果:
![]()
而若是咱們在一、2之間執行一次commit操做,就變成了:
因而可知,Mybatis的二級緩存是跨Session的,每一個Mapper享有同一個二級緩存域,一樣,每次執行commit操做以後,一樣會清空緩存。
Mybatis這麼好,如何應用呢?
由於這是一種緩存機制嘛,只有相對於實時性要求不高的需求才會使用緩存機制,它也同樣。對於訪問多的查詢請求且用戶對查詢結果實時性要求不高,此時可採用mybatis二級緩存技術下降數據庫訪問量,提升訪問速度,業務場景好比:耗時較高的統計分析sql、電話帳單查詢sql等。 實現方法以下:經過設置刷新間隔時間,由mybatis每隔一段時間自動清空緩存,根據數據變化頻率設置緩存刷新間隔flushInterval,好比設置爲30分鐘、60分鐘、24小時等,根據需求而定。
但是,好歸好,Mybatis也有它必定的侷限性。那就是Mybatis對於細粒度的數據級別的緩存實現的不是太好,也就是若是同Mapper下的商品類別繁多的話,他不能實現只刷新某固定商品的信息,而只能全盤刷新。當時將這塊的時候我想過讓Mapper水平分區不就好了,但是後來講到Mybatis的二級緩存是以命名空間劃分的或者說是以Mapper劃分,無論咱們怎麼水平劃分,只要命名空間同樣,那就只共享一個二級緩存域,當刷新的時候仍是會全Mapper更新一遍。