1. 程式人生 > >mybatis高階知識(四)&查詢快取

mybatis高階知識(四)&查詢快取

1.查詢快取

1.1什麼是查詢快取

mybatis提供查詢快取,用於減輕資料壓力,提高資料庫效能
mybatis提供一級快取二級快取


一級快取是SQLSession級別的快取
    在操作資料庫時需要構造SQLSession物件,在物件中有一個數據結構(HashMap)使用者儲存快取資料
不同的SQLSession之間的快取資料的區域(HashMap)是互不影響的。

二級快取是mapper級別的快取
    多個SQLSession去操作同一個Mapper的sql語句,多個SqlSession可以共用二級快取,二級快取是SQLSession的

為什麼要儲存?
    如果快取中有資料就不用在從資料庫中獲取,大大提高系統的效能。

2一級快取

    2.1一級快取的工作原理
        第一次發起查詢使用者id為1的使用者的資訊,先去找快取中是否有id為1的使用者資訊,如果沒有,從資料庫查詢使用者
        資訊
        得到使用者資訊,將使用者資訊儲存到一級儲存中

        如果在SQLSession去執行commit操作(執行插入,更新,刪除)清空SQLSession中的一級快取。這樣做的目的
        為了快取中永遠儲存的是最新的資訊,避免髒讀       
        第二次發起查詢使用者id為1的使用者資訊,先去查詢快取中是否有id為1的使用者資訊,快取中有,直接從快取中獲取
        使用者資訊
    2.2一級快取測試
        mybatis預設支援一級快取,不需要在配置檔案去配置
        按照上邊一級快取原理步驟測試
測試程式碼
            public testCacher1() throws Exception{
            SqlSession sqlSesssion=sqlSessionFactory.openSession();//建立代理物件
            UserMapper userMapper=sqlSession.getMapper(UserMapper.class);
                //下邊查詢使用一個SqlSession
                //第一次發起請求,查詢id為1的使用者
                User uyser=userMapper.findUserById
(1); System.out.println(:user1); //如果SQLSession去執行commit操作(執行插入,更新,刪除) 清空SQLSession中的一級快取 這樣做的目的是為了讓快取中儲存的是最新的資訊,避main髒讀 //更新user的資訊 user.setUsername(“測試使用者22”); userMapper.updateUser(user1); //執行commint操作去清除快取 SQLSession.commit(); //第二次發起請求,查詢id為1的使用者 User user2=username.fiondUserById(1); System.out.println(user2); sqlSession.close(); }
    2.3一級快取的應用
    正式開發,是將mybatis和spring進行整合開發,事務空載子service中
    一個service方法中包括很多mapper方法呼叫
    service
        //開始執行執行時,開啟事務,建立SQLSession物件
        //第一呼叫mapper的方法findUserByID(1);
        //第二次呼叫mapper的方法findUserByID(1);從一級快取中取資料
        //方法結束sqlSession關閉
    如果是倆次service呼叫查詢相同的使用者資訊,不走一級快取,因為service方法結束,SQLSession就關閉
    一級快取就清空。    

3.二級快取

    首先開啟mybatis的二級快取
    SQLSession去查詢使用者id為1的使用者資訊,查詢到使用者資訊會將查詢資料儲存到二級快取中
    如果SQLSession去執行相同mapper下sql,執行commit提交,清空該mapper下的二級快取區域的資料
    SQLSession去查詢使用者id為1的使用者資訊,去快取中查中是否存在資料,如果存在直接從快取中取出資料
    二級快取與一級快取區別:二級快取的範圍更大,多個SQLSession可以共享一個UserMapper二級快取
    UserMapper有一個二級快取區域(按照namespace分),其他的mapper也有自己的快取區域(按照namespace分)
    每一個namespace的mapper有一個二級快取區域,如果倆個mapper的namespace如果相同,這倆個
    mapper執行sql查詢到的資料就存在相同的二級快取區域中
3.1開啟二級快取
mybatis的二級快取是mapper範圍級別,除了在SqlMapConfig.xml設定二級快取的總開關,還要在具體的mapper.xml
        中開啟二級快取
        二級快取使用,需要在主檔案中進行配置:
            ①啟用二級快取
            <!-- 啟用二級快取 -->
            <setting name="cacheEnabled" value="true"/>

    在UserMapper中開啟二級快取,UserMapper.xml下的sql執行完成會儲存到它的快取區域(HashMap)、
    <mapper namespace="mybaties.mapper.User,apper">
    <!--開啟本mapper的namespace下的二級快取-->
    <cache/>
3.2呼叫pojo類實現序列化介面
public class User implements Serializables{
        private int id;
        private String username;
        private String sex;
        private Date birthday;
        private String address;
    }
為了將快取的資料取出執行序列化操作,因為二級快取的儲存介質多種多樣,不一定在記憶體

3.3測試方法
public testCacher2() throws Exception{
            SqlSession sqlSesssion=sqlSessionFactory.openSession();
            SqlSession sqlSesssion2=sqlSessionFactory.openSession();
            SqlSession sqlSesssion3=sqlSessionFactory.openSession();

            //建立代理物件
            UserMapper userMapper=sqlSession.getMapper(UserMapper.class);

                //下邊查詢使用一個SqlSession
                //第一次發起請求,查詢id為1的使用者
                User uyser=userMapper.findUserById(1);
                System.out.println(:user1);
                //這裡執行關閉操作,將SQLSession中的資料寫到二級快取區域
                SQLSession.close();             

                //使用SQLSession執行commit()操作
                UserMapper userMapper3=sqlSession3.getMapper(UserMapper.class);
                User user=userMapper3.findUserById(1);
                user.setUsername(“測試使用者22”);
                userMapper3.updateUser(user1);
                //執行commint操作去清除快取
                SQLSession3.commit();
                SQLSession3.close();

                UserMapper userMapper2=sqlSession2.getMapper(UserMapper.class);
                //第二次發起請求,查詢id為1的使用者
                User user2=userMapper2.findUserById(1);
                Stystem.out.println(user2);
                sqlSession2.close();


            }
    3.4useCache配置
    ①.設定useCache=false可以禁用當前select語句的二級快取,即每次查詢都會發出sql去查詢,預設情況是true,即該sql使用二級快取。
    <select id="findOrderListResultMap" resultMap="ordersUserMap" useCache="false">
    總結:針對每次查詢都需要最新的資料sql,要設定成useCache=false,禁用二級快取。
    ②.清空快取
    <insert id="insertUser" parameterType="cn.itcast.mybatis.po.User" flushCache="true"> 
    總結:一般下執行完commit操作都需要重新整理快取,flushCache=true表示重新整理快取,這樣可以避免資料庫髒讀。
    注意:

    (1)當為select語句時:

    flushCache預設為false,表示任何時候語句被呼叫,都不會去清空本地快取和二級快取。

    useCache預設為true,表示會將本條語句的結果進行二級快取。

    (2)當為insert、update、delete語句時:

    flushCache預設為true,表示任何時候語句被呼叫,都會導致本地快取和二級快取被清空。

    useCache屬性在該情況下沒有。

    當為select語句的時候,如果沒有去配置flushCache、useCache,那麼預設是啟用快取的,所以,如果有必要,那麼就需要人工修改配置

    4.mybatis整合ehcache
        4.1分散式快取
        我們系統為了提高系統併發,效能。一般對系統進行分散式部署。(叢集部署方式)
        不使用分佈緩衝池快取的資料在各自伺服器單獨儲存,不方便系統開發,所以要對分散式快取對快取資料進行集中管理
        mybatis無法實現分散式快取。需要和其他分散式快取框架進行整合
        4.2整合的方法
        mybatis提供了一個cache介面,如果要實現自己的儲存邏輯,實現cache介面開發即可
        mybatis和ehcache整合,mybatis和ehcache集合包中提供了一個cache介面的實現類
public interface Cache{
                String getId();
                void putObject(Object key ,Object value);
                Object getObject(Object key);


            }
        mybatis預設實現的cache類是
        public class PerpetualCache implements Cache{
            private String id;
            private Map<Object,Object> cache=new HashMap<Object,Object>();
            public PerpetualCache(String id){
                this.id=id;

            }
            public String getId(){
                return id;
            }
        }

4.3配置資訊
配置mapper中的cache中的type為ehcache對cache介面的實現
    <mapper namespace="mybatis.mapper.UserMapper">
        <!-- 開啟mapper的namespace下的二級快取
            type:指定Cache介面的實現類的型別,mybatis預設使用PerpetualCache
            要和ehcache整合:需要配置type為ehcache實現cache介面型別
            -->
        <caahe type="org.mybatis.caches.ehcache.EhcacheCache"/>
    3.4加入ehcache包
    ehcache-core-2.6.5.jar
    mybatis-ehcache-1.0.2jar

    3.5加入ehcache的配置檔案
在classpath下配置
             1 <ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             2 xsi:noNamespaceSchemaLocation="../config/ehcache.xsd">
             3 <diskStore path="F:\develop\ehcache" />
             4 <defaultCache
             5 maxElementsInMemory="1000"
             6 maxElementsOnDisk="10000000"
             7 eternal="false"
             8 overflowToDisk="false"
             9 timeToIdleSeconds="120"
            10 timeToLiveSeconds="120"
            11 diskExpiryThreadIntervalSeconds="120"
            12 memoryStoreEvictionPolicy="LRU">
            13 </defaultCache>
            14 </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二級快取應用場景
        應用場景:

   對於訪問多的查詢請求且使用者對查詢結果實時性要求不高,此時可採用mybatis二級快取技術降低資料庫訪問量,提高訪
問速度,業務場景比如:耗時較高的統計分析sql、電話賬單查詢sql等。實現方法如下:通過設定重新整理間隔時間,由mybatis每隔一段時
間自動清空快取,根據資料變化頻率設定快取重新整理間隔flushInterval,比如設定為30分鐘、60分鐘、24小時等,根據需求而定。

    5.侷限性:
  mybatis二級快取對細粒度的資料級別的快取實現不好,比如如下需求:對商品資訊進行快取,由於商品資訊查詢訪問量大,
但是要求使用者每次都能查詢最新的商品資訊,此時如果使用mybatis的二級快取就無法實現當一個商品變化時只重新整理該商品的緩
存資訊而不重新整理其它商品的資訊,因為mybaits的二級快取區域以mapper為單位劃分,當一個商品資訊變化會將所有商品資訊
的快取資料全部清空。解決此類問題需要在業務層根據需求對資料有針對性快取。