ehcacheキャッシュ実戦


前述のMyBatis 2次キャッシュについては、ehcache、ehcacheがMybatisの2次キャッシュとしてどのように構成されているかなどを簡単に紹介しました.この文章はehcacheのより上層部での応用を紹介する.ehcacheの2次キャッシュをできるだけ早く使用すると、Mybatisのクエリー効率を最適化できますが、これにはいくつかの制限があります.
1.キャッシュは、【単一テーブルのみの操作】テーブルでのみ使用可能
このテーブルがシステム全体で単一のテーブルのみで動作することを保証するだけでなく、テーブルに関連するすべての操作が1つのnamespaceの下にある必要があります.
2.クエリがinsert,update,deleteよりはるかに大きいことを保証できる場合にキャッシュを使用する
この点は多く言う必要はありません.誰もが知っているはずです.覚えておいてください.この点は1の前提の下で保証する必要があります.
実際には2次キャッシュの使用を避けるべきであり、mybatisの2次キャッシュには次のような特徴があります.
>*      namespacenamespace        。

>*  insert,update,delete       namespace      。

>*      MyBatis Generator      ,        ,        namespace

2次キャッシュの使用を避ける理由
最初に述べた2次キャッシュの制限に合致する場合、影響はありません.
他の状況には多くの危害があります.
1つのテーブルに対するいくつかの操作は、独立したnamespaceの下では行われません.
たとえば、UserMapper.xmlにはuserテーブルに対する操作がほとんどあります.ただし、1つのXXXXmapper.xmlでは、user単一テーブルに対する操作もあります.
これにより、userの2つのネーミングスペースでのデータが一致しなくなります.UserMapper.xmlでキャッシュをリフレッシュする操作を行った場合、XXXXmapper.xmlでキャッシュがまだ有効であり、userに対する単一テーブルクエリがある場合、キャッシュを使用した結果が正しくない可能性があります.
さらに危険なのは、XXXXmapper.xmlがinsert,update,delete操作を行った場合(この時点ですべてのキャッシュがクリアされる)、UserMapper.xmlの様々な操作が未知とリスクに満ちていることです.
このような単一テーブルに関する操作は一般的ではないかもしれません.しかし、よくあることを考えたかもしれません.
マルチテーブル操作ではキャッシュは使用できません
どうしてできないの?
まず、複数のテーブル操作がそのnamespaceの下に書かれていても、あるテーブルがこのnamespaceの下にない場合があります.
たとえば、roleとuserの2つのテーブルrole、あるユーザーのすべてのロールroleをクエリーしたい場合は、必ずマルチテーブルの操作に関連します.
<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に書いても構いません.2次キャッシュを使用すると、上記のクエリの結果が正しくない可能性があります.
このユーザーのロールをちょうど変更した場合、上のクエリがキャッシュを使用している間に結果が間違っています.
この点は分かりやすいはずだ.
私から見れば、MyBatisの現在のキャッシュ方式では理解できません.マルチテーブル操作ではキャッシュできません.
同じnamespace(<cache-ref>)を使用して汚いデータを避けると、キャッシュの意味がなくなります.
二次キャッシュを救いますか?
2次キャッシュをより効率的に使用するには解決できません.
しかし、マルチテーブル操作を解決して汚いデータを避けるには解決できません.解決策は,実行されたsqlがそれらのテーブル(jsqlparserで解析可能)に関連しているとブロックによって判断し,関連テーブルのキャッシュを自動的に空にすることである.しかし、この方式はキャッシュの使用効率が低い.
このようなプラグインを設計するのはかなり複雑で、私が実現しようとしない以上、くだらないことはありません.
最後に、2次キャッシュを放棄し、ビジネス層で制御可能なキャッシュを使用することをお勧めします.
ビジネス層はehcache実戦を使用します.
libディレクトリに次のjarパッケージを追加する必要があります.
ehcache-core-2.5.2.jar

ehcache-web-2.0.4.jar //        

3、現在のプロジェクトのsrcディレクトリにプロファイルを追加する
ehcache.xml

ehcache.xsd

これらのプロファイルはehcache-coreというjarパッケージで見つけることができます.
Ehcacheの基本的な使い方
CacheManager cacheManager = CacheManager.create();
//   
cacheManager = CacheManager.getInstance();
//   
cacheManager = CacheManager.create("/config/ehcache.xml");
//   
cacheManager = CacheManager.create("http://localhost:8080/test/ehcache.xml");
cacheManager = CacheManager.newInstance("/config/ehcache.xml");
// .......

//   ehcache        cache
Cache sample = cacheManager.getCache("sample");
//       
BlockingCache cache = new BlockingCache(cacheManager.getEhcache("SimplePageCachingFilter"));
//         
Element element = new Element("key", "val");
sample.put(element);
//         ,     cache          Serializable  
Element result = sample.get("key");
//     
sample.remove("key");
sample.removeAll();

//                
for (String cacheName : cacheManager.getCacheNames()) {
    System.out.println(cacheName);
}
//          
for (Object key : cache.getKeys()) {
    System.out.println(key);
}

//          
cache.getSize();
//              
cache.getMemoryStoreSize();
//            
cache.getStatistics().getCacheHits();
//            
cache.getStatistics().getCacheMisses();

三、ページキャッシュ
ページキャッシュは、要求されたurlがキャッシュに表示された場合、主にFilterフィルタでフィルタされます.すると、ページデータはキャッシュオブジェクトから取得され、gzipで圧縮されて返されます.キャッシュを圧縮していない場合の3~5倍の速度で、かなりの効率です.ここで、ページキャッシュのフィルタにはCachingFilterがあり、一般的にフィルタを拡張したり、カスタムFilterをカスタマイズしたりしてCachingFilterを継承します.CachingFilter機能は、HTTP応答のコンテンツをキャッシュすることができる.この方法では、ページ全体をキャッシュするなど、データの粒度が比較的太い.その利点は使用が簡単で、効率が高く、欠点は柔軟ではなく、再利用可能な程度が高くないことです.
EHCacheはSimplePageCachingFilterクラスを用いてFilterキャッシュを実現する.このクラスはCachingFilterから継承され、HTTPリクエストのURIとクエリー条件を使用してkeyを構成するcache keyをデフォルトで生成するcalculateKey()メソッドがあります.独自にFilterを実装し、CachingFilterクラスを継承し、calculateKey()メソッドを上書きしてカスタムkeyを生成することもできます.
CachingFilterから出力されたデータは、ブラウザから送信されたAccept-Encodingヘッダ情報に基づいてGzip圧縮されます.
Gzip圧縮を使用する場合は、次の2つの問題に注意してください.
  • FilterはGzip圧縮を行う際にシステムデフォルト符号化を採用しており、GBK符号化を用いた中国語ページではオペレーティングシステムの言語をzh_に設定する必要があるCN.GBK、そうでないと文字化けの問題が発生します.

  • デフォルトでは、CachingFilterは、ブラウザから送信された要求ヘッダに含まれるAccept-Encodingパラメータ値に基づいてGzip圧縮を行うか否かを判断します.IE 6/7ブラウザはGzip圧縮をサポートしていますが、リクエストを送信する際にはこのパラメータを持っていません.IE 6/7に対してもGzip圧縮を行うためには、CachingFilterを継承することにより独自のFilterを実現し、具体的な実装においてメソッドacceptsGzipEncodingを上書きすることができる.


  • 具体的な実装の参考:
    protected boolean acceptsGzipEncoding(HttpServletRequest request) {
    
    boolean ie6 = headerContains(request, "User-Agent", "MSIE 6.0");
    
    boolean ie7 = headerContains(request, "User-Agent", "MSIE 7.0");
    
    return acceptsEncoding(request, "gzip") || ie6 || ie7;
    
    }

    ehcache.xmlの構成は次のとおりです.
    <?xml version="1.0" encoding="gbk"?>
    <ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="ehcache.xsd">
        <diskStore path="java.io.tmpdir"/>
    
        <defaultCache maxElementsInMemory="10000" eternal="false" timeToIdleSeconds="30" timeToLiveSeconds="30" overflowToDisk="false"/>
        <!--         maxElementsInMemory:              eternal:           ,   ,        ,      。 timeToIdleSeconds:         ,            ,               ,               ,       0                 。 timeToLiveSeconds:         ,                     ,                ,     0                。 overflowToDisk:     ,        。 memoryStoreEvictionPolicy:           。   :  ehcache.xml        cache  ,               cache,  name     。 -->
        <cache name="SimplePageCachingFilter" maxElementsInMemory="10000" eternal="false" overflowToDisk="false" timeToIdleSeconds="900" timeToLiveSeconds="1800" memoryStoreEvictionPolicy="LFU" />
    
    </ehcache>

    Web.xmlに次の構成を追加します.
    <!-- ehcache -->
        <filter>
            <filter-name>SimplePageCachingFilter</filter-name>
            <filter-class>net.sf.ehcache.constructs.web.filter.SimplePageCachingFilter
            </filter-class>
          </filter>
    
      <!-- This is a filter chain. They are executed in the order below. Do not change the order. -->
         <filter-mapping>
            <filter-name>SimplePageCachingFilter</filter-name>
            <url-pattern>*.do</url-pattern>
         </filter-mapping>

    注意:ehcache.xmlファイルで構成されているキャッシュ名は、web.xml構成のキャッシュフィルタ名と一致する必要があります.そうしないと、構成の例外が見つかりません.
    これらのページが最初に要求されると、これらのページはキャッシュに追加され、後で要求されるページはキャッシュから取得されます.cache.jspページで、ページがキャッシュされているかどうかを足でテストできます.<%=新Date()%>時間が変動している場合は、ページがキャッシュされていないか、キャッシュが期限切れになっているかを示します.そうしないと、キャッシュ状態になります.
    オブジェクトキャッシュ
    オブジェクトキャッシュとは、クエリーのデータをキャッシュに追加し、次に再クエリーするときにデータベースからクエリーせずにキャッシュから直接取得することです.
    オブジェクトキャッシュは一般的にメソッド、クラスに対して行われますが、SpringのAopオブジェクト、メソッドキャッシュを組み合わせると簡単です.ここでは,SpringのMethodInterceptorまたは@Aspectを用いた切面プログラミングが必要である.
    public class MethodCacheInterceptor implements MethodInterceptor, InitializingBean {
    
        private static final Logger log = Logger.getLogger(MethodCacheInterceptor.class);
    
        private Cache cache;
    
        public void setCache(Cache cache) {
            this.cache = cache;
        }
    
        public void afterPropertiesSet() throws Exception {
            log.info(cache + " A cache is required. Use setCache(Cache) to provide one.");
        }
    
        public Object invoke(MethodInvocation invocation) throws Throwable {
            String targetName = invocation.getThis().getClass().getName();
            String methodName = invocation.getMethod().getName();
            Object[] arguments = invocation.getArguments();
            Object result;
    
            String cacheKey = getCacheKey(targetName, methodName, arguments);
            Element element = null;
            synchronized (this) {
                element = cache.get(cacheKey);
                if (element == null) {
                    log.info(cacheKey + "     : " + cache.getName());
                    //        
                    result = invocation.proceed();
                    element = new Element(cacheKey, (Serializable) result);
                    cache.put(element);
                } else {
                    log.info(cacheKey + "    : " + cache.getName());
                }
            }
            return element.getValue();
        }
    
        /** * <b>function:</b>                 * @param targetName     * @param methodName      * @param arguments    * @return        */
        private String getCacheKey(String targetName, String methodName, Object[] arguments) {
            StringBuffer sb = new StringBuffer();
            sb.append(targetName).append(".").append(methodName);
            if ((arguments != null) && (arguments.length != 0)) {
                for (int i = 0; i < arguments.length; i++) {
                    sb.append(".").append(arguments[i]);
                }
            }
            return sb.toString();
        }
    }

    ここでのメソッドブロッカーは、主にブロックするクラスのメソッドをブロックし、そのメソッドのクラスパス+メソッド名+パラメータ値の組み合わせのcache keyがキャッシュcacheに存在するかどうかを判断します.存在する場合はキャッシュからオブジェクトを取り出し、戻りタイプに変換します.ない場合は,このメソッドで返されたオブジェクトをキャッシュに追加すればよい.現在のメソッドのパラメータと戻り値のオブジェクトタイプをシーケンス化する必要があることが考えられます.
    srcディレクトリの下にアプリケーションContext.xmlを追加して、MethodCacheInterceptorブロッキングの構成を完了する必要があります.この構成は主に私たちのcacheオブジェクトを注入し、どのcacheがオブジェクトキャッシュを管理し、その後、どのクラス、方法がブロッキングのスキャンに参加するかです.
    <!--   eh      -->
    <bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean"/>
    
    <!--            bean   -->
    <bean id="simpleCache" class="org.springframework.cache.ehcache.EhCacheFactoryBean">
        <property name="cacheManager" ref="cacheManager" />
        <!--        ehcache.xml       -->
        <property name="cacheName" value="mobileCache" />
    </bean>
    
    <!--            ,          -->
    <bean id="methodCacheInterceptor" class="com.common.interceptor.MethodCacheInterceptor">
        <property name="cache" ref="simpleCache"/>
    </bean>
    
    <!--            (     ,           ) -->
    <bean id="methodCachePointCut" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
        <!--     aop   -->
        <property name="advice" ref="methodCacheInterceptor" />
        <!--              -->
        <!-- .           ### +               ### *               ### \Escape  Regular expression       -->                 
        <!-- .*       (    )   print  -->
        <property name="patterns">
            <list>
                <value>com.hoo.rest.*RestService*\.*get.*</value>
                <value>com.hoo.rest.*RestService*\.*search.*</value>
            </list>
        </property>
    </bean>

    ehcache.xmlに次のcache構成を追加します.
    <cache name="mobileCache" maxElementsInMemory="10000" eternal="false" overflowToDisk="true" timeToIdleSeconds="1800" timeToLiveSeconds="3600" memoryStoreEvictionPolicy="LFU" />

    参照先:http://blog.csdn.net/isea533/article/details/44566257 参照先:http://www.cnblogs.com/hoojo/archive/2012/07/12/2587556.html