mybatis缓存机制详解(一)——Cache

缓存概述

在mybatis中,缓存的功能由根接口Cache(org.apache.ibatis.cache.Cache)定义。整个体系采用装饰器设计模式,数据存储和缓存的基本功能由PerpetualCache(org.apache.ibatis.cache.impl.PerpetualCache)永久缓存实现,然后通过一系列的装饰器来对PerpetualCache永久缓存进行缓存策略等方便的控制。如下图:

用于装饰PerpetualCache的标准装饰器共有8个(全部在org.apache.ibatis.cache.decorators包中):

1.FifoCache:先进先出算法,缓存回收策略

2.LoggingCache:输出缓存命中的日志信息

3.LruCache:最近最少使用算法,缓存回收策略

4.ScheduledCache:调度缓存,负责定时清空缓存

5.SerializedCache:缓存序列化和反序列化存储

6.SoftCache:基于软引用实现的缓存管理策略

7.SynchronizedCache:同步的缓存装饰器,用于防止多线程并发访问

8.WeakCache:基于弱引用实现的缓存管理策略

另外,还有一个特殊的装饰器TransactionalCache:事务性的缓存


正如大多数持久层框架一样,mybatis缓存同样分为一级缓存和二级缓存

一级缓存,又叫本地缓存,是PerpetualCache类型的永久缓存,保存在执行器中(BaseExecutor),而执行器又在SqlSession(DefaultSqlSession)中,所以一级缓存的生命周期与SqlSession是相同的

二级缓存,又叫自定义缓存,实现了Cache接口的类都可以作为二级缓存,所以可配置如encache等的第三方缓存。二级缓存以namespace名称空间为其唯一标识,被保存在Configuration核心配置对象中。如下:

public class Configuration {
    // ...
    protected final Map<String, Cache> caches = new StrictMap<Cache>("Caches collection");
    // ...
}

每次构建SqlSessionFactory对象时都会创建新的Configuration对象,因此,二级缓存的生命周期与SqlSessionFactory是相同的。在创建每个MapperedStatement对象时,都会根据其所属的namespace名称空间,给其分配Cache缓存对象。


二级缓存对象的默认类型为PerpetualCache,如果配置的缓存是默认类型,则mybatis会根据配置自动追加一系列装饰器。

Cache对象之间的引用顺序为:

SynchronizedCache-->LoggingCache-->SerializedCache-->ScheduledCache-->LruCache-->PerpetualCache


所有的缓存对象的操作与维护都是由Executor器执行来完成的,一级缓存由BaseExecutor(包含SimpleExecutor、ReuseExecutor、BatchExecutor三个子类)负责维护,二级缓存由CachingExecutor负责维护。因此需要注意的是:配置了二级缓存不代表mybatis就会使用二级缓存,还需要确保在创建SqlSession的过程中,mybatis创建是CachingExecutor类型的执行器。

Executor中对Cache的具体操作逻辑,请点击mybatis核心组件详解——Executor


源码解读:

Cache接口:

package org.apache.ibatis.cache;

import java.util.concurrent.locks.ReadWriteLock;


/**
 * 缓存接口
 * 给缓存供应商的SPI(Service Provider Interface)
 * 一个Cache的实例将为名称空间被创建
 * Cache接口的实现类必须有一个具有String类型参数的构造方法,用于接收Cache对象的id,作为其唯一标识
 * 
 * mybatis将以namespace作为id调用这个构造函数创建对象
 * 
 * @author Administrator
 *
 */
public interface Cache {

    /**
     * 获取缓存对象的唯一标识
     * @return
     */
    String getId();

    /**
     * 保存key/value到缓存对象中
     * key可以是任何对象,但一般是CacheKey对象
     * value是查询结果,为List类型
     * @param key
     * @param value
     */
    void putObject(Object key, Object value);

    /**
     * 从缓存对象中获取key对应的value
     * @param key
     * @return
     */
    Object getObject(Object key);

    /**
     * 可选的方法,没有被核心框架调用,移除key对应的value
     * @param key
     * @return
     */
    Object removeObject(Object key);

    /**
     * 清空缓存
     */
    void clear();

    /**
     * 获取缓存对象中存储的键/值对的数量
     * 可选的方法,没有被框架核心调用
     */
    int getSize();

    /**
     * 获取读写锁
     * 可选的方法,从3.2.6起这个方法不再被框架核心调用
     * 任何需要的锁,都必须由缓存供应商提供
     * 
     * @return A ReadWriteLock
     */
    ReadWriteLock getReadWriteLock();

}

PerpetualCache永久缓存:

package org.apache.ibatis.cache.impl;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.ReadWriteLock;

import org.apache.ibatis.cache.Cache;
import org.apache.ibatis.cache.CacheException;

/**
 * 永久缓存 Cache接口实现类
 * Cache接口只有这唯一一个基础实现,其他实现类全都是装饰模式持有另一个缓存对象
 * 
 * @author Administrator
 *
 */
public class PerpetualCache implements Cache {
    // 缓存对象的唯一标识
    private String id;
    // 对象内部维护的HashMap
    private Map<ObjectObject> cache = new HashMap<ObjectObject>();

    public PerpetualCache(String id) {
        this.id = id;
    }

    public String getId() {
        return id;
    }

    public int getSize() {
        return cache.size();
    }

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

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

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

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

    public ReadWriteLock getReadWriteLock() {
        return null;
    }

    public boolean equals(Object o) {
        if (getId() == null)
            throw new CacheException("Cache instances require an ID.");
        if (this == o)
            return true;
        if (!(o instanceof Cache))
            return false;

        Cache otherCache = (Cache) o;
        return getId().equals(otherCache.getId());
    }

    public int hashCode() {
        if (getId() == null)
            throw new CacheException("Cache instances require an ID.");
        return getId().hashCode();
    }

}

在mybatis中,PerpetualCache是唯一的Cache接口的基础实现。它内部维护一个HashMap,所有的缓存操作,其实都是对这个HashMap的操作。

其他Cache接口的实现类全部为装饰器,源码详解请点击mybatis缓存机制详解(二)——缓存装饰器

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值