缓存使用
一、本地缓存
1.说明
- 本地缓存 LocalCache,即 JVM 缓存,适用于存储访问频率高,缓存数据集又不是很大的场合,缓存类定义在 localcache.xml 里。 
- 本地缓存又分为本地只读缓存、本地读写缓存两类。 
- 本地只读缓存,要求缓存数据一次性全量加载,确保缓存 100% 命中。[推荐] 
- 本地读写缓存,适合那些没法一次性全量加载的场合,采用按需加载方式,即先看缓存有没有,没有再查数据库或读文件,再将数据缓存起来。 
2.本地只读缓存
业务级缓存类要求继承 AbstractReadOnlyCache,实现 loadData 接口,返回一个 Map
示例代码:
配置示例:
<localcaches>    
    <!-- 只读缓存,数据需要一次性全量加载。-->
    <readonly>
        <!--
            className: 缓存实现类  (必配参数)
            cronExpr: 缓存清理时间 (可选参数,默认不自动清空。)
            init: 系统初始化时是否立即初始化缓存 (可选参数, 默认不初始化)
        -->
        <cache className="com.ailk.biz.cache.CacheTablesCache" cronExpr="30 1 * * ?" init="true" />
    </readonly>
    <readwrite>
        ......略
    </readwrite>
</localcaches>
缓存定义示例:
public class CacheTablesCache extends AbstractReadOnlyCache {
    @Override
    public Map<String, Object> loadData() throws Exception {
        Map<String, Object> rtn = new HashMap<String, Object>();
        IDataInput input = new DataInput();
        IDataOutput output = ServiceFactory.call("SYS_CacheTables_GetList", input);
        IDataset datas = output.getData();
        for (int i = 0, size = datas.size(); i < size; i++) {
            IData data = datas.getData(i);
            String tableName = data.getString("TABLE_NAME");
            String version = data.getString("VERSION");
            // 版本号只取"日时分", 格式:(DDHHMI),够用的情况下越短越好。
            version = StringUtils.replaceChars(version, ":- ", "").substring(6, 12);
            rtn.put(tableName, version);
        }
        return rtn;
    }
}
使用示例:
// 获取版本号缓存
IReadOnlyCache cache = CacheFactory.getReadOnlyCache(CacheTablesCache.class);
String version = (String) cache.get(tableName);
3.本地读写缓存
配置示例:
<localcaches>    
    <readonly>
        ......略
    </readonly>
    <!-- 读写缓存,数据按需加载,采用LRU淘汰机制。 -->
    <readwrite>
        <!--
            name: 缓存名 (必配参数)
            maxSize: 最大缓存记录数 (可选参数,默认10000条)
            cronExpr: 缓存清理时间 (可选参数,默认不自动清空。)
        -->
        <cache name="COMMON_CACHE" maxSize="10000" cronExpr="29 10 * * ?" />
    </readwrite>
</localcaches>
使用示例
IReadWriteCache cache = CacheFactory.getReadWriteCache("COMMON_CACHE");
String cacheValue = cache.get(cacheKey);
if (null == cacheValue) {
    cacheValue = ... // 查数据库或读文件
    if (null != cacheValue) {
        cache.put(cacheKey, cacheValue);
    }
}
4.备注
CacheFactory类简介:本次缓存工厂类 。初始化时候,通过static静态块,自动加载localcache.xml配置文件,读取本地化的只读缓存和读写缓存配置。然后执行initReadOnlyCaches和initReadWriteCaches方法,获取缓存。代码如下:
public final class CacheFactory {
    private static List<ReadOnlyCacheItem> readonlyCacheItems;
    private static List<ReadWriteCacheItem> readwriteCacheItems;
    static {
        try {
            CacheXml cacheXml = CacheXml.getInstance(); // 读取localcache.xml配置文件
            readonlyCacheItems = cacheXml.getReadOnlyCacheItems();
            readwriteCacheItems = cacheXml.getReadWriteCacheItems();
            initReadOnlyCaches(readonlyCacheItems); // 初始化本地只读缓存
            initReadWriteCaches(readwriteCacheItems); // 初始化本地读写缓存
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
二、分布式缓存
1.说明
- 缓存数据是基于集群的异构分布式存放,一份数据只会存放在一个节点; 
- 客户端通过 Key 的一致性 hash 算法唯一确定缓存节点,并按段存取; 
- 当缓存节点退出或新增时,只会影响故障节点的数据,并将按需重新加载; 
- 支持定时与实时的数据增量刷新; 
- 自定义 Memcached 客户端,采用 Hessian 序列化 Java 对象; 
- 通过客户端心跳线程对 MC 长连接做健康检测; 
- 支持超大对象(>1M)的数据压缩(Gzip)存储。 
注:这里着重介绍memcache
2.配置说明
配置示例:
<?xml version = '1.0' encoding = 'UTF-8'?>
<memcache>
    <datacenter name="center1" >
        <!-- 默认一中心的APP只连一中心的CCD,备节点在二中心 -->
        <cluster name="codecode_cache"> 
            <heartbeat-second>2</heartbeat-second>
            <pool-size>5</pool-size>
            <address master="IP1:11301" slave="IP3:11311" />
            <address master="IP1:11302" slave="IP3:11312" />
            <address master="IP2:11301" slave="IP4:11311" />
            <address master="IP2:11302" slave="IP4:11312" />
        </cluster>
        <!-- 默认一中心的APP只连一中心的STATIC CACHE,备节点在二中心 -->
        <cluster name="staticparam_cache">
            <heartbeat-second>2</heartbeat-second>
            <pool-size>5</pool-size>
            <address master="IP1:11401" slave="IP3:11411" />
            <address master="IP1:11402" slave="IP3:11412" />
            <address master="IP2:11401" slave="IP4:11411" />
            <address master="IP2:11402" slave="IP4:11412" />
        </cluster>        
    </datacenter>
    <datacenter name="center2" >
        <cluster name="shc_cache">
            <heartbeat-second>2</heartbeat-second>
            <pool-size>5</pool-size>
            <address master="IP1:11101" slave="IP3:11111" />
            <address master="IP2:11101" slave="IP4:11111" />
            <address master="IP3:11101" slave="IP1:11111" />
            <address master="IP4:11101" slave="IP2:11111" />
        </cluster>
    </datacenter>
    <!-- 指明服务连接的中心。注: 只支持后模糊匹配 -->
    <server name="app-node01-*"   connect="center1" />
    <server name="app-node02-*"   connect="center2" />
</memcache>
注:通过server的模糊匹配,找到配置节点。然后通过cluster的name,找到对应的一组缓存的地址和端口。
3.使用实例
IMemCache memCache = null;
memCache = MemCacheFactory.getCache("codecode_cache");
IDataset datas = (IDataset) memCache.get(cacheKey);
if (null != datas) {
        // 如果memcache里面有,则直接返回
    return datas;
} else {
    // 如果没有,查询数据库获取,并放置到memcache中以便下次直接获取
    IDataset datas = ccdao.queryList(sql, param, pagination);
    memCache.set(cacheKey, datas);
}
注:文档来源于Wade官网缓存文档说明