计算机有两大基本的功能:计算和存储。在存储方面,缓存的设计和实现也是一门学问。这门学问里面包含什么门道呢?不妨研究一下MyBatis缓存类PerpetualCache,一定会大有收获的。

在MyBatis里面,存在一个PerpetualCache,它是一级缓存、二级缓存的最基本实现,但PerpetualCache只不过包装了一下HashMap。Perpetual是"永久、不间断"之意,以PerpetualCache为根本,在cache.decorators包里面有多种缓存的代理,实现了各种清除策略。

1、PerpetualCache 名字的含义

Perpetual是"永久、不间断"之意,为什么这么命名呢?稍加联系,便能明白。缓存的设计有两个重点问题:如何存储数据和采用何种清除策略。存储的话,用哈希表即可完美解决。对于清除策略而言,往往有多种选择。MyBatis作者Clinton Begin选择Perpetual来命名缓存,暗示这是一个最底层的缓存,数据一旦存储进来,永不清除,如果实现清除策略,请把Perpetual包装一下。在cache.decorators包里面有多种缓存,它们内部串联的主线就是按照“不同的清除策略”来贯穿的。

PerpetualCache.jpg

2、PerpetualCache的实现原理:

PerpetualCache仅仅是包装了HashMap,代码如下所示:

public class PerpetualCache implements Cache 
{

  private final String id;

  private Map<Object, Object> cache = new HashMap<Object, Object>();

}

PerpetualCache的读取数据,也是通过内部的HashMap来实现的,代码如下所示:

@Override
public void putObject(Object key, Object value) {
cache.put(key, value);
}

@Override
public Object getObject(Object key) {
return cache.get(key);
}

@Override
public Object removeObject(Object key) {
return cache.remove(key);
}

@Override
public void clear() {
cache.clear();
}

3、Key的设计:CacheKey

在PerpetualCache内部使用的Java自带的HashMap:

Map<Object, Object> cache = new HashMap<Object, Object>();

但是,HashMap的Key设计略显单薄,无法适应复杂的缓存场景,需要进行自定义设计。MyBatis实现了CacheKey类,其功能非常的强大。

public class CacheKey implements Cloneable, Serializable
{
    private final int multiplier;
    private int hashcode;
    private long checksum;
    private int count;
    private List<Object> updateList;
}

代码分析如下所示:

(1)hashcode,用于表示CacheKey的哈希码
(2)checksum,总和校验,当出现复合key的时候,分布计算每个key的哈希码,然后求总和
(3)count,当出现复合key的时候,计算key的总个数
(4)updateList,当出现复合key的时候,保存每个key

CacheKey这个类设计的非常好,个人推荐感兴趣的人可以仔细读一读其源码。其初始化的过程如下所示:

public CacheKey(Object[] objects)
{
    this();
    updateAll(objects);
}

public void updateAll(Object[] objects)
{
    for (Object o : objects)
    {
        update(o);
    }
}

public void update(Object object)
{
    int baseHashCode = object == null ? 1 : ArrayUtil.hashCode(object);

    count++;
    checksum += baseHashCode;
    baseHashCode *= count;

    hashcode = multiplier * hashcode + baseHashCode;

    updateList.add(object);
}

标签: none

添加新评论