MyBatis二級緩存應用場景以及局限性

應用場景:

對於訪問多的查詢請求且用戶對查詢結果實時性要求不高,此時可採用mybatis二級緩存技術降低數據庫訪問量,提高訪問速度,業務場景比如:耗時較高的統計分析sql、電話賬單查詢sql等。

實現方法如下:通過設置刷新間隔時間,由mybatis每隔一段時間自動清空緩存,根據數據變化頻率設置緩存刷新間隔flushInterval,比如設置為30分鐘、60分鐘、24小時等,根據需求而定。

侷限性:

mybatis二級緩存對細粒度的數據級別的緩存實現不好,比如如下需求:對商品信息進行緩存,由於商品信息查詢訪問量大,但是要求用戶每次都能查詢最新的商品信息,

此時如果使用mybatis的二級緩存就無法實現當一個商品變化時只刷新該商品的緩存信息而不刷新其它商品的信息,因為mybaits的二級緩存區域以mapper為單位劃分,

當一個商品信息變化會將所有商品信息的緩存數據全部清空。解決此類問題需要在業務層根據需求對數據有針對性緩存。

緩存都是實現了Cache這個接口.....

如何開啟 二級緩存,步驟如下:

1.導入ehcache相關jar包 (ehcache: 緩存插件,插件:就是對現有應用軟件功能的一個擴展)


ehcache-core-2.6.5.jar mybatis-ehcache-1.1.0.jar <dependency> <groupid>net.sf.ehcache/<groupid> <artifactid>ehcache-core/<artifactid> <version>2.6.6/<version> <dependency> <groupid>org.mybatis.caches/<groupid> <artifactid>mybatis-ehcache/<artifactid> <version>1.1.0/<version>

2,開啟mybatis的二級緩存


在mybatis核心配置文件mybatis-config.xml中加入 <settings> <setting>

3.在classpath下加入ehcache.xml文件


<ehcache> <diskstore> <defaultcache> maxElementsInMemory="10000" eternal="false" timeToIdleSeconds="120" timeToLiveSeconds="120" overflowToDisk="true" maxElementsOnDisk="10000000" diskPersistent="false" diskExpiryThreadIntervalSeconds="120" memoryStoreEvictionPolicy="LRU" />/<defaultcache>

屬性說明:

 diskStore:指定數據在磁盤中的存儲位置。

 defaultCache:當藉助CacheManager.add("demoCache")創建Cache時,EhCache便會採用<defalutcache>指定的的管理策略

以下屬性是必須的:

 maxElementsInMemory - 在內存中緩存的element的最大數目

 maxElementsOnDisk - 在磁盤上緩存的element的最大數目,若是0表示無窮大

 eternal - 設定緩存的elements是否永遠不過期。如果為true,則緩存的數據始終有效,如果為false那麼還要根據timeToIdleSeconds,timeToLiveSeconds判斷

 overflowToDisk - 設定當內存緩存溢出的時候是否將過期的element緩存到磁盤上

以下屬性是可選的:

 timeToIdleSeconds - 當緩存在EhCache中的數據前後兩次訪問的時間超過timeToIdleSeconds的屬性取值時,這些數據便會刪除,默認值是0,也就是可閒置時間無窮大

 timeToLiveSeconds - 緩存element的有效生命期,默認是0.,也就是element存活時間無窮大

diskSpoolBufferSizeMB 這個參數設置DiskStore(磁盤緩存)的緩存區大小.默認是30MB.每個Cache都應該有自己的一個緩衝區.

 diskPersistent - 在VM重啟的時候是否啟用磁盤保存EhCache中的數據,默認是false。

 diskExpiryThreadIntervalSeconds - 磁盤緩存的清理線程運行間隔,默認是120秒。每個120s,相應的線程會進行一次EhCache中數據的清理工作

 memoryStoreEvictionPolicy - 當內存緩存達到最大,有新的element加入的時候, 移除緩存中element的策略。默認是LRU(最近最少使用),可選的有LFU(最不常使用)和FIFO(先進先出) 4.在UserMapper.xml中開啟二緩存,UserMapper.xml下的sql執行完成會存儲到它的緩存區域(HashMap)


<cache> <property> <property> <property> <property> <property> <cache> <cache>

測試:需求獲取員工表所有記錄數(測試二級緩存),

執行一次查詢後,關閉session;然後獲得一個全新的Session,再執行查詢,若此時控制檯未輸出sql語句,且磁盤相應緩存目錄下有緩存文件產生,證明二級緩存發揮了作用。

sql映射文件中:


<cache> <property>
<property> <property> <property> <property>

dao實現類中:


@Override public List<person> selectAll() {/<person> //步驟: //通過工具類獲得SqlSession的實例 SqlSession sqlSession = MyBatisUtil.getSqlSessionInstance(); List<person> persons = sqlSession.selectList("com.uplooking.dao.PersonDao.selectAll");/<person> System.out.println("第一次查詢到的員工數是:" + persons); //關閉sqlSession(讓一級緩存失效) MyBatisUtil.releaseResource(sqlSession); //執行完下面的代碼行,控制檯若沒有sql語句輸出,證明結果來自於二級緩存,而不是重新查詢的數據庫。 sqlSession = MyBatisUtil.getSqlSessionInstance(); persons = sqlSession.selectList("com.uplooking.dao.PersonDao.selectAll"); System.out.println("第二次查詢到的員工數是:" + persons); //釋放資源 MyBatisUtil.releaseResource(sqlSession); return persons; }

建議:放棄二級緩存,在業務層使用可控制的緩存代替更好。

<select>

select * from user_role a,role b where a.roleid = b.roleid and a.userid = #{userid}

像上面這個查詢,你會寫到那個xml中呢??

不管是寫到RoleMapper.xml還是UserRoleMapper.xml,或者是一個獨立的XxxMapper.xml中。如果使用了二級緩存,都會導致上面這個查詢結果可能不正確。

如果你正好修改了這個用戶的角色,上面這個查詢使用緩存的時候結果就是錯的。