天天看点

Mybatis自定义二级缓存-下

前言

        在前一篇博客里面讲了如何实现Mybatis二级缓存的自定义,但是并没有一个完整的实现,并且还没有详解如何使用二级缓存等。这篇文章就来结束这个系列。

选取缓存介质

        在这里的话,我们需要来选取一个合适的缓存介质,对于我们而言,Mybatis的二级缓存是基于namespace的,这也就为多台机器共用二级缓存提供了可能性。也正因为如此,我们不可能将缓存放在本机的内存中,类似于Mybatis官方给的那个HashMap实现的例子是不可能的。当然,Enhance之类的内存缓存也就不可能了。

        对此,我们选择的一个策略是Redis。

自定义二级缓存实现

        实际上,首先我们要做的是确定我们将要依赖那些东西,因此,我们需要在此处做的事情就是,确定我们依赖的jar。如下为我的pom文件。

<dependencies>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.6</version>
        </dependency>
        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
            <version>2.8.0</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.3.0</version>
        </dependency>
        <dependency>
            <groupId>com.weimob</groupId>
            <artifactId>soa-common</artifactId>
            <version>1.0.1-SNAPSHOT</version>
        </dependency>
    </dependencies>
           

        好了,接下来,让我们来看代码的实现。

import java.util.Map;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import org.apache.ibatis.cache.Cache;
import redis.clients.jedis.ShardedJedis;
import redis.clients.jedis.ShardedJedisPool;

public class RedisCache implements Cache {

    private final ReadWriteLock readWriteLock = new ReentrantReadWriteLock();

    private String id;

    private static ShardedJedisPool pool;

    public RedisCache(final String id) {
        if (id == null) {
            throw new IllegalArgumentException("Cache instances require an ID");
        }
        this.id = id;
    }

    private Object execute(RedisCallback callback) {
        ShardedJedis jedis = pool.getResource();
        try {
            return callback.doWithRedis(jedis);
        } finally {
            jedis.close();
        }
    }

    @Override
    public String getId() {
        return this.id;
    }

    @Override
    public int getSize() {
        return (Integer) execute(new RedisCallback() {
            @Override
            public Object doWithRedis(ShardedJedis jedis) {
                Map<byte[], byte[]> result = jedis.hgetAll(id.toString().getBytes());
                return result.size();
            }
        });
    }

    @Override
    public void putObject(final Object key, final Object value) {
        execute(new RedisCallback() {
            @Override
            public Object doWithRedis(ShardedJedis jedis) {
                jedis.hset(id.toString().getBytes(), key.toString().getBytes(), SerializeUtilRedis.serialize(value));
                return null;
           

        这里的话实际上采取了回调,如下为回调的接口:

public interface RedisCallback {

    Object doWithRedis(ShardedJedis jedis);
}
           

        采取这个回调的好处是我们可以让所有的增删改查等方法有统一的格式,我们不关注方法自己的实现,但是我们为他提供了标准。

        其中的序列化等操作实际上借用FastJson的就可以完成,在此不是重点。不予以讲解。

如何使用

        刚才讲的是道,就是如何去实现。现在我们讲解的是术。如何做。实际上很简单,就是在mapper文件中简单配置下。

总结

        这两篇文章详细的讲解了如何通过Mybatis为我们预留的接口扩展它的二级缓存。你可以使用各种各样的介质。去完成自己的需求。

思考

        我们来思考下二级缓存适合使用在什么地方,事实上,这里的二级缓存是以namespace为单位存储的,这也造成了他有一个致命的缺陷。那就是只要这个namespace对应的sql发生增删改等操作,那么所有的缓存都会被清掉。这也就是说二级缓存适用的范围就是必须要求查询大量而别的操作很少的情形。当然,如果这种缓存满足不了你,那就只能写到业务代码里面了。

继续阅读