MyBatisの2次キャッシュとしてRedis Clusterを使用し、protostuffを使用してデータをシーケンス化


ほとんどの永続層フレームワークと同様に、MyBatisは1次キャッシュと2次キャッシュのサポートを提供しています.レベル1キャッシュはPerpetualCacheのHashMapローカルキャッシュに基づいており、そのストレージ役割ドメインはSessionであり、Session flushまたはcloseの後、Session内のすべてのCacheがクリアされます.2次キャッシュは、1次キャッシュと同じメカニズムで、デフォルトではPerpetualCache、HashMapストレージが使用されます.これは、ストレージの役割ドメインがMapper(Namespace)であることと、Ehcache、Redisなどのストレージソースをカスタマイズできることです.
この文書では、Mybatisの2次ストレージ・ソースとしてRedisを使用し、protostuffシーケンス化キャッシュ・データを使用すると、ストレージ領域が節約されます.キャッシュの堅牢性のためにRedisクラスタを使用した.
依存の追加
         <dependency>
            <groupId>redis.clientsgroupId>
            <artifactId>jedisartifactId>
            <version>2.9.0version>
            <scope>compilescope>
         dependency>
           <dependency>
            <groupId>io.protostuffgroupId>
            <artifactId>protostuff-coreartifactId>
            <version>1.4.4version>
        dependency>
        <dependency>
            <groupId>io.protostuffgroupId>
            <artifactId>protostuff-runtimeartifactId>
            <version>1.4.4version>
        dependency>

2次キャッシュを開くmybatis-config.xmlはcacheEnabledを変更する:
"cacheEnabled" value="true"/>

二次キャッシュはNameSpaceに定義されているため、二次キャッシュをMappingファイルで開く必要があります.ラベルを追加するだけでいいです.もちろん、このラベルにはキャッシュ回収ポリシーeviction、リフレッシュ時間flushInterval、キャッシュ数size、読み取り専用キャッシュreadOnlyなどの他のプロパティがあります.Mybatisを構成するために注釈を使用している場合(Springと統合)、@Mapperのクラスを追加する場合は、@CacheNamespace注釈を使用して2次キャッシュを開く必要があります.同様に、この注釈はキャッシュのメタデータの構成をサポートします.以前に所属していたように、Mybatisのデフォルトの2次キャッシュはPerpetualCacheであり、2次キャッシュをカスタマイズし、キャッシュキャリアをRedisに設定する必要があります.
カスタム2次キャッシュMyBatisには、import orgというインタフェースがあります.apache.ibatis.cache.Cache.カスタム2次キャッシュは、インタフェースを実装するだけです.
public interface Cache {
String getId();
int get Size();
void putObject(Object key, Object value);
Object getObject(Object key);
Object removeObject(Object key);
void clear();
ReadWriteLock getReadWriteLock();
}

ただし、putObject()とgetObject()の2つのメソッドに重点を置く必要があります.その前にRedisクラスタを構築する.Redisクラスタの構築Redisクラスタには2種類あり、1つはredis sentinelであり、高利用可能なクラスタであり、同時に1つのmasterしかなく、各インスタンスのデータが一致している.1つはredis cluster,分散クラスタであり,同時に複数のmasterがあり,各masterにデータスライスが配置されている.本稿ではredis clusterモードを構築し、redis公式ドキュメントで非常に詳細に説明します.http://www.redis.cn/topics/cluster-tutorial.html.最終的に6つのRedisサービスが開始され、confは以下のように構成されます.
port 7000/7001/7002/7003/7004/7006
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
appendonly yes

redis-server xxxを通ります.conf.起動に成功するにはredis-tribを使用する必要があります.rbは、6つのクラスタが1~16384個のハッシュスロットを共有し始めるハッシュスロット分割を行う(Redisサービスごとに1~16384個のハッシュスロットを持つ).
クラスタの作成:
./redis-trib.rb create --replicas 1 127.0.0.1:7000 127.0.0.1:7001 \
127.0.0.1:7002 127.0.0.1:7003 127.0.0.1:7004 127.0.0.1:7005

-replicas 1は、クラスタ内の各プライマリノードにスレーブノードを作成することを示します.この結果、最終的には3つのプライマリノードが含まれ、各プライマリノードにスレーブノードが1つ存在します.redis-cli -h127.0.0.1 -p 7000 cluster nodesを使用してクラスタの状態を確認できます.クラスタに新しいRedisマシンを追加したい場合は、ハッシュスロットを再割り当てするためにコマンドを呼び出すことができます.具体的には、ここでは説明せずに、関連ドキュメントをクエリーすることができます.
クラスタ構築が完了したら、jedisクライアントで直接BinaryJedisClusterを介して呼び出せばよい.
   public BinaryJedisCluster getJedis(){
        Set jedisClusterNodes = new HashSet();
        jedisClusterNodes.add(new HostAndPort("127.0.0.1", 7000));
        //xxxx
        BinaryJedisCluster jc = new BinaryJedisCluster(jedisClusterNodes);
        return jc;
    }

protostuffシーケンス化Protostuffのシーケンス化について筆者は以前ブログの紹介を書いたことがある(http://blog.csdn.net/canot/article/details/53750443)、ここでは述べずにCacheを実装したコードを直接与える.

```@Component
public class RedisCache implements Cache {
    private BinaryJedisCluster redisTemplate = getJedis();
    private final ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
    private  String id; // cache instance id
    private static final int EXPIRE_TIME_IN_MINUTES = 60*60; // redis    
    private static RuntimeSchema schema = RuntimeSchema.createFrom(CacheEntry.class);

    public RedisCache(){

    }
    public RedisCache(String id){
        if (id == null) {
            throw new IllegalArgumentException("Cache instances require an ID");
        }
        this.id = id;
    }
    /*
     *mybatis          。  mapper    mybatis       。
     */
    @Override
    public String getId() {
        return id;
    }
    /*
     *         
     */
    @Override
    public void putObject(Object key, Object value) {
    //     ArrayList
        ArrayList valueList = (ArrayList)value;
        CacheEntry cacheEntry = new CacheEntry(valueList);
        //  protostuff   
        byte[] bytesValue = ProtostuffIOUtil.toByteArray(cacheEntry,schema, LinkedBuffer.allocate(LinkedBuffer.DEFAULT_BUFFER_SIZE));
        byte[] bytesKey = key.toString().getBytes(Charset.forName("UTF-8"));
 //   Redis
redisTemplate.setex(bytesKey,EXPIRE_TIME_IN_MINUTES,bytesValue);
    }
    /*
     *               。
     */
    @Override
    public Object getObject(Object key) {
        byte[] bytesKey = key.toString().getBytes(Charset.forName("UTF-8"));
        byte[] bytesValue = redisTemplate.get(bytesKey);
        CacheEntry value = schema.newMessage();
        if(bytesValue!=null) {
            ProtostuffIOUtil.mergeFrom(bytesValue, value, schema);
            return value.getSeckills();
        }
        //    null,        
        return null;

    }
    /*
     *         key、value。      
     */
    @Override
    public Object removeObject(Object key) {
        redisTemplate.del(key.toString().getBytes(Charset.forName("UTF-8")));
        return null;
    }
    /*
     *         key、value
     */
    @Override
    public void clear() {
        //redisTemplate.flushDB();
       //       ,     
    }
    /*
     *     
     */
    @Override
    public int getSize() {
        return 1024;
    }
    /*
    *              
    */
    @Override
    public ReadWriteLock getReadWriteLock() {
        return readWriteLock;
    }

    public BinaryJedisCluster getJedis(){
        Set jedisClusterNodes = new HashSet();
        jedisClusterNodes.add(new HostAndPort("127.0.0.1", 7000));
        //xxxx
        BinaryJedisCluster jc = new BinaryJedisCluster(jedisClusterNodes);
        return jc;
    }

}
class CacheEntry{
    private List seckills;
    public CacheEntry(List seckills){
        this.seckills=seckills;
    }
    public List getSeckills() {
        return seckills;
    }
    public void setSeckills(List seckills) {
        this.seckills = seckills;
    }
}

Cacheは、2次キャッシュまたは@CacheNamespace(implementation = package.RedisCache.class)に設定される
二次キャッシュの使用に関する注意事項
  • は、「単一テーブルのみの操作」のテーブルでのみキャッシュ
  • を使用できる.
    このテーブルがシステム全体で単一のテーブルのみで動作することを保証するだけでなく、テーブルに関連するすべての操作が1つのnamespaceの下にある必要があります.
  • クエリーがinsert,update,delete操作よりはるかに大きいことを保証できる場合、キャッシュ
  • を使用する.
    この点は多く言う必要はありません.誰もが知っているはずです.覚えておいてください.この点は上記の前提の下で保証する必要があります.
  • マルチテーブル操作は必ずキャッシュ
  • を使用できない.
    複数のテーブル操作がそのnamespaceの下に書き込まれても、あるテーブルがこのnamespaceの下にない場合があります.汚れて読む場合があります.