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>
<!-- https://mvnrepository.com/artifact/org.mybatis.caches/mybatis-ehcache -->
<dependency>
<groupId>org.mybatis.caches</groupId>
<artifactId>mybatis-ehcache</artifactId>
<version>1.1.0</version>
</dependency>
        2,開啟mybatis的二級緩存          

在mybatis核心配置文件mybatis-config.xml中加入

            <settings>
                <!-- 開啟二級緩存 -->
                <setting name="cacheEnabled" value="true" />
            </settings>
      3.在classpath下加入ehcache.xml文件
          

<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../config/ehcache.xsd">

<diskStore path="java.io.tmpdir"/>

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

<!--
默認緩存配置,
以下屬性是必須的:
name :cache的標識符,在一個CacheManager中必須唯一。
maxElementsInMemory : 在內存中緩存的element的最大數目。
maxElementsOnDisk : 在磁盤上緩存的element的最大數目。
eternal : 設定緩存的elements是否有有效期。如果為true,timeouts屬性被忽略。
overflowToDisk : 設定當內存緩存溢出的時候是否將過期的element緩存到磁盤上。
以下屬性是可選的:
timeToIdleSeconds : 緩存element在過期前的空閑時間。
timeToLiveSeconds : 緩存element的有效生命期。
diskPersistent : 在VM重啟的時候是否持久化磁盤緩存,默認是false。
diskExpiryThreadIntervalSeconds : 磁盤緩存的清理線程運行間隔,默認是120秒.
memoryStoreEvictionPolicy : 當內存緩存達到最大,有新的element加入的時候,
移除緩存中element的策略。默認是LRU,可選的有LFU和FIFO
-->
</ehcache>
        屬性說明:
         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 type="org.mybatis.caches.ehcache.EhcacheCache">
                <!-- timeToLiveSeconds 緩存自創建日期起至失效時的間隔時間 -->
                <property name="timeToIdleSeconds" value="3600" />

                <!-- timeToIdleSeconds 緩存創建以后,最后一次訪問緩存的日期至失效之時的時間間隔 -->
                <property name="timeToLiveSeconds" value="3600" />

                <!-- 同ehcache參數maxElementsInMemory -->
                <property name="maxEntriesLocalHeap" value="1000" />

                <!-- 同ehcache參數maxElementsOnDisk -->
                <property name="maxEntriesLocalDisk" value="10000000" />
                
                <!-- 當內存緩存達到最大,有新的element加入的時候, 移除緩存中element的策略。默認是LRU(最近最少使用),可選的有LFU(最不常使用)和FIFO 
                    (先進先出) -->
                <property name="memoryStoreEvictionPolicy" value="LRU" />
     </cache>


            <!--mybatis ehcache緩存配置 -->
            <!-- 以下兩個<cache>標簽二選一,第一個可以輸出日志,第二個不輸出日志 -->
             <cache type="org.mybatis.caches.ehcache.LoggingEhcache" />
           
             <cache type="org.mybatis.caches.ehcache.EhcacheCache"/> 
    測試:需求獲取員工表所有記錄數(測試二級緩存),
          執行一次查詢后,關閉session;然后獲得一個全新的Session,再執行查詢,若此時控制台未輸出sql語句,且磁盤相應緩存目錄下有緩存文件產生,證明二級緩存發揮了作用。     
    
sql映射文件中:

<cache type="org.mybatis.caches.ehcache.EhcacheCache">
        <!-- timeToLiveSeconds 緩存自創建日期起至失效時的間隔時間 -->
        <property name="timeToIdleSeconds" value="3600" />

        <!-- timeToIdleSeconds 緩存創建以后,最后一次訪問緩存的日期至失效之時的時間間隔 -->
        <property name="timeToLiveSeconds" value="3600" />

        <!-- 同ehcache參數maxElementsInMemory -->
        <property name="maxEntriesLocalHeap" value="1000" />

        <!-- 同ehcache參數maxElementsOnDisk -->
        <property name="maxEntriesLocalDisk" value="10000000" />

        <!-- 當內存緩存達到最大,有新的element加入的時候, 移除緩存中element的策略。默認是LRU(最近最少使用),可選的有LFU(最不常使用)和FIFO
            (先進先出) -->
        <property name="memoryStoreEvictionPolicy" value="LRU" />
    </cache>    
dao實現類中:

@Override
    public List<Person> selectAll() {
        //步驟:
        //通過工具類獲得SqlSession的實例
        SqlSession sqlSession = MyBatisUtil.getSqlSessionInstance();

        List<Person> persons = sqlSession.selectList("com.uplooking.dao.PersonDao.selectAll");
        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 id="selectUserRoles" resultType="UserRoleVO">
    select * from user_role a,role b where a.roleid = b.roleid and a.userid = #{userid}
</select>
像上面這個查詢,你會寫到那個xml中呢??
不管是寫到RoleMapper.xml還是UserRoleMapper.xml,或者是一個獨立的XxxMapper.xml中。如果使用了二級緩存,都會導致上面這個查詢結果可能不正確。
如果你正好修改了這個用戶的角色,上面這個查詢使用緩存的時候結果就是錯的。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM