踏踏實實踏踏實實,開開心心,開心是一天不開心也是一天,路漫漫其修遠兮。
--WZY
一、延遲加載
延遲加載就是懶加載,先去查詢主表信息,如果用到從表的數據的話,再去查詢從表的信息,也就是如果沒用到從表的數據的話,就不查詢從表的信息。所以這就是突出了懶這個特點。真是懶啊。
Mybatis中resultMap可以實現延遲加載
1.1、查詢訂單信息,延遲加載用戶信息,一對一關系。
1.1.1、開啟延遲加載
全局配置文件中,settings標簽用來設置全局常量的,這里就用到了。

1 <settings> 2 //打開延遲加載的開關,默認為true 3 <setting name="lazyLoadingEnabled" value="true"/> 4 //積極的懶加載,默認是true,設置為false時,懶加載生效 5 <setting name="aggressiveLazyLoading" value="false"/> 6 </settings>
1.1.2、編寫主表信息的查詢映射
也就是先查詢orders
這里asscciation中property中的user為OrderExt中的一個user屬性。注意區分。
1.1.3、編寫從表的查詢映射,findUserById
1.2、小總結
很簡單,就三步
1、開啟延遲加載
2、編寫主表的查詢映射
3、編寫從表的查詢映射
2、3兩步通俗點講就是將其分開來,並不是向之前一樣,一次性全寫了,注意這點就OK了。
二、緩存機制
緩存的作用是什么?
mybatis提供查詢緩存,如果緩存中有數據就不用從數據庫中獲取,用於減輕數據壓力,提高系統性能,
mybatis中分兩個緩存,一級緩存和二級緩存,現在來講講這兩個緩存,也同樣很easy。
2.1、一級緩存
一級緩存是SqlSession級別的緩存。在操作數據庫時需要構造 sqlSession對象,在對象中有一個數據結構(HashMap)用於存儲緩存數據。不同的sqlSession之間的緩存數據區域(HashMap)是互相不影響的
過程分析
第一次查詢id為1 的用戶,此時先去一級緩存查找,如果查找不到,則去數據庫查詢,把查詢后的 結果存儲到一級緩存中
第二次查詢id為1 的用戶,此時先去一級緩存查找,如果查找到,則直接從一級緩存中把數據取出,不去查詢數據庫
只要中間發生增刪改操作,那么一級緩存就清空
默認開啟一級緩存
注意:第二步中,修改,添加,刪除是對緩存中已經有的記錄進行這三個操作才會把一級緩存全部清空,如果是操作的緩存中沒有的數據,那么就不會清空緩存。
測試的話就不測試了,也不需要配置什么東西開啟,默認開啟的,如果感興趣,那么就對其進行測試。
2.2、二級緩存
二級緩存是mapper級別的緩存,多個SqlSession去操作同一個Mapper的sql語句,多個SqlSession可以共用二級緩存,二級緩存是跨SqlSession的
過程分析
第一次查詢id為1 的用戶,此時先去二級緩存查找,如果查找不到,則去數據庫查詢,把查詢后的 結果存儲到二級緩存中
第二次查詢id為1 的用戶,此時先去二級緩存查找,如果查找到,則直接從二級緩存中把數據取出,不去查詢數據庫
只要中間發生增刪改操作,那么二級緩存就清空
二級緩存默認不開啟,需要手動開啟。
跟一級緩存差不多,只是二級緩存是mapper級別的,也就是每個sqlSession共享該緩存,而不是每個sqlSession獨享。
一級緩存和二級緩存的作用范圍圖
關系:當開啟了二級緩存時,那么一級緩存就失效了,大家都共享二級緩存,相當於沒有一級緩存,不管干什么都是對二級緩存進行操作。這里跟hibernate的緩存有區別,不要搞混淆了。
使用mybatis自帶的二級緩存
5.2.1、開啟二級緩存
第一步:在全局配置文件中開啟
第二步:在映射文件中開啟二級緩存的開關
因為使用的是自帶的,所以直接寫cache即可,如果使用的是第三方緩存框架,那么這里就需要寫東西了,后面會講解到。
5.2.2、序列化對象
二級緩存中的數據,可以存儲到磁盤中,因為緩存中存儲的是對象,所以需要對對象進行一個序列化
不開啟序列化,則會報下面的錯誤
5.2.3、這樣二級緩存就開啟了,下次在查詢或者別的操作,就會使用二級緩存。
5.2.4、刷新緩存
在映射文件的statement標簽,可以設置是否刷新緩存。這個要注意,
注意,這里先不看userCache這個標簽。在下面會講解到
該statement中設置flushCache=true可以刷新當前的二級緩存,默認情況下
select語句:flushCache是false,也就是默認情況下,select語句是不會刷新緩存的。
如果設置成true,那么每次查詢都市去數據庫查詢,意味着查詢的二級緩存失效
insert、update、delete語句:flushCache是true,也就是默認情況下,增刪改是會刷新緩存的。
如果增刪改設置為false,即使用二級緩存,那么如果在數據庫中修改了數據,而緩存數據還是原來的,這個時候就會出現問題。
所以一般不用手動設置,使用默認的即可。
5.2.5、禁用緩存
該statement中設置userCache=false,可以禁用當前select語句的二級緩存,即每次查詢都是去數據庫中查詢,默認情況下是true,即該statement使用二級緩存
三、Mybatis整合使用ehcache
ehcache是一個分布式緩存框架(集群部署)
3.1、集群是什么意思?
比如開發一個電商網站,訪問的人數太多,服務器壓力太大,所以想到一個方法,就是將該項目發布到幾個服務器上,讓用戶訪問過來,隨機分配一個服務器,這樣幾個服務器就均攤了壓力,但是這樣有一個問題,A用戶第一次訪問網站,隨機發配到了B服務器,瀏覽了很多商品,也緩存了很多數據,此時A不小心關閉了瀏覽器,接着在進行訪問,這次隨機分配到了C服務器,此時緩存卻沒有了,因為不是同一個服務器,那么怎么解決這個緩存問題呢?此時就有一種方法來解決。看下圖
所以集群就是將很多服務器集中起來一起進行同一種服務,這里進行的服務就是對緩存數據進行集中管理。
3.2、為什么使用第三方緩存框架?
其實上面已經解釋過了,Mybatis它是一個持久層的框架,不是一個緩存框架。所以說她本身的緩存機制不是很好,不能支持分布式,所以需要對它進行整合,整合其他的分布式緩存框架,在之前對hibernate中的二級緩存,也是使用的ehcache,之后我們還會學到一個redis的緩存框架
3.3、整合緩存框架(例如ehcache)
前提是也需要開啟二級緩存的開關呀,比如在全局配置文件中打開開關,具體看上面
3.3.1、了解
Mybatis提供了一個cache接口,同時它自己有一個默認的實現類PerpetualCache
cache接口
默認的實現類PerpetualCache
在我們使用mybatis默認的二級緩存時,在映射文件中只寫了一個cache,其中就是默認使用的mybatis默認的二級緩存,也就是這個實現類,如果整合其他緩存框架的話,那么就需要改變了,下面會講解到,現在這里了解一下。
3.3.2、添加ehcache的jar包
3.3.3、添加ehcache的配置文件
創建ehcache.xml文件,文件內容如下

1 <ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 2 xsi:noNamespaceSchemaLocation="../config/ehcache.xsd"> 3 <!-- 緩存數據要存放的磁盤地址 --> 4 <diskStore path="F:\develop\ehcache" /> 5 <!-- diskStore:指定數據在磁盤中的存儲位置。 defaultCache:當借助CacheManager.add("demoCache")創建Cache時,EhCache便會采用<defalutCache/>指定的的管理策略 6 以下屬性是必須的: maxElementsInMemory - 在內存中緩存的element的最大數目 maxElementsOnDisk 7 - 在磁盤上緩存的element的最大數目,若是0表示無窮大 eternal - 設定緩存的elements是否永遠不過期。如果為true,則緩存的數據始終有效,如果為false那么還要根據timeToIdleSeconds,timeToLiveSeconds判斷 8 overflowToDisk - 設定當內存緩存溢出的時候是否將過期的element緩存到磁盤上 以下屬性是可選的: timeToIdleSeconds 9 - 當緩存在EhCache中的數據前后兩次訪問的時間超過timeToIdleSeconds的屬性取值時,這些數據便會刪除,默認值是0,也就是可閑置時間無窮大 10 timeToLiveSeconds - 緩存element的有效生命期,默認是0.,也就是element存活時間無窮大 diskSpoolBufferSizeMB 11 這個參數設置DiskStore(磁盤緩存)的緩存區大小.默認是30MB.每個Cache都應該有自己的一個緩沖區. diskPersistent 12 - 在VM重啟的時候是否啟用磁盤保存EhCache中的數據,默認是false。 diskExpiryThreadIntervalSeconds 13 - 磁盤緩存的清理線程運行間隔,默認是120秒。每個120s,相應的線程會進行一次EhCache中數據的清理工作 memoryStoreEvictionPolicy 14 - 當內存緩存達到最大,有新的element加入的時候, 移除緩存中element的策略。默認是LRU(最近最少使用),可選的有LFU(最不常使用)和FIFO(先進先出) --> 15 16 <defaultCache maxElementsInMemory="1000" 17 maxElementsOnDisk="10000000" eternal="false" overflowToDisk="false" 18 timeToIdleSeconds="120" timeToLiveSeconds="120" 19 diskExpiryThreadIntervalSeconds="120" memoryStoreEvictionPolicy="LRU"> 20 </defaultCache> 21 </ehcache>
3.3.4、在mapper映射文件中設置cache標簽的type
3.3.5、這樣就整合完成了。
四、總結
看了一遍之后,是不是覺得都不難,其實確實是不難,明白了怎么回事就差不多了,但是到了實際用起來又是一回事,現在只是知道是什么,怎么去用還需要等到實際開發中慢慢體會。這里提一下,使用二級緩存的局限性
二級緩存對細粒度的數據緩存效果不好,什么意思呢?
場景:對商品信息進行緩存,由於商品信息查詢訪問量大,但是要求用戶每次查詢都是最新的商品信息,此時如果使用二級緩存,就無法實現當一個商品發生變化只刷新該商品的緩存信息而不刷新其他商品緩存信息,因為二級緩存是mapper級別的,當一個商品的信息發送更新,所有的商品信息緩存數據都會清空
解決此類問題,需要在業務層根據需要對數據有針對性的緩存,比如可以對經常變化的 數據操作單獨放到另一個namespace的mapper中
其他沒什么,這個是順帶說一下,具體開發中肯定會有很多對應的方法的,不過二級緩存確實有這樣的缺點。有問題就有解決的方法。
mybatis差不多就快要結束了,下一節將講與spring整合和逆向工程了。加油。