Java内存缓存 memory cache

wwwmr1909 贡献于2014-03-26

作者 sunny  创建于2013-02-20 13:09:00   修改者sunny  修改于2013-02-20 13:09:00字数3214

文档摘要:基于数据库的应用系统中,经常有必要根据ID获取编号或者名称,这是因为我们设计数据库,一般按照“三范式”来设计数据库,业务数据表中只存放主数据的ID。而根据ID获取编号或者名称,通常是使用SQL实时查询。每次都查询数据库,数据库负荷不小,这部分其实可以优化。网络上常见的cache,包括ehcache/oscache/apachejcs,只适合于cache业务数据(transactiondata),而不适合于cache主数据(masterdata)。还动不动就分布式缓存,其实没有必要。现在内存这么便宜,开个4G内存缓存,可以缓存n多数据,足够很多系统用的了。
关键词:

基于数据库的应用系统中,经常有必要根据 ID 获取编号或者名称,这是因为我们设计数据库,一般按照“三范式”来设计数据库,业务数据表中只存放主数据的 ID。而根据 ID 获取编号或者名称,通常是使用 SQL 实时查询。每次都查询数据库,数据库负荷不小,这部分其实可以优化。   网络上常见的 cache , 包括 ehcache/oscache/apache jcs, 只适合于 cache 业务数据(transaction data),而不适合于 cache 主数据(master data)。还动不动就分布式缓存,其实没有必要。现在内存这么便宜,开个 4G 内存缓存,可以缓存 n 多数据,足够很多系统用的了。   这里的业务数据(transaction data)指的是数据量随时间线性增长的数据,主数据(master data)指的是数据量不随时间线性增长的数据(不增长或增长很慢)。   这两个数据在缓存处理逻辑上的差别有: 1. 业务数据(transaction data) 的缓存一般只缓存最近使用的数据(Least Recently Used Cache);主数据(master data)的缓存是所有数据。 2. 两种数据都需要定期更新缓存:业务数据(transaction data) 的缓存更新是逐个进行;主数据(master data)的缓存更新是按分类,某种数据一起性地全更新。 3. 业务数据(transaction data) 的缓存,需要定时清除长时间不用的数据;主数据(master data)的缓存,不需要清除长时间不用的数据。   最近突然意识到,有必要做一个工具类/工具包,用于主数据(master data)的缓存。可以在多个项目中复用。      首先定义 cache 的公共接口,有两个操作:数据一起性全更新 reload(), 定义数据过期时间 getReloadPeriodMillis(). 这样便有了这个类:   为了排版,以下代码中用了中文全角空格!!!    package org.velocityweb.cache; import java.util.Map; /** * interface for period lazy reload cache, normally for master data translating id to name/code * * @author Jacklondon Chen * */ public interface PeriodicLazyReloadCache {   /**    * get reload period in millis-seconds    *    * @return    */   public long getReloadPeriodMillis();   /**    * reload data invalid for timeout    *    * @param bufferMap    */   public void reload(Map bufferMap); } 再定义个“内存、周期性更新、延迟加载的缓存”  类 MemPeriodicLazyReloadCacheProvider,用于加载数据,更新缓存: package org.velocityweb.cache; import java.util.Collections; import java.util.HashMap; import java.util.Map; /** * memory cache for period lazy reload cache, normally for master data translating id to name/code. Use this for * small-scale data cache. This class is thread safe. * * @author Jacklondon Chen * */ public class MemPeriodicLazyReloadCacheProvider {   PeriodicLazyReloadCache cache;   volatile Map bufferMap = null;   volatile long lastReloadTime = -1;   /**    * constructor for MemPeriodicLazyReloadCacheProvider    *    * @param cache    *      cache implement    */   public MemPeriodicLazyReloadCacheProvider(PeriodicLazyReloadCache cache) {     this.cache = cache;   }   /**    * get data from cache    *    * @param key    * @return    */   public synchronized Object get(Object key) {     long timePassed = System.currentTimeMillis() - lastReloadTime;     if (timePassed > cache.getReloadPeriodMillis()) {       Map newBufferMap = createBufferMap();       cache.reload(newBufferMap);       this.bufferMap = newBufferMap;       lastReloadTime = System.currentTimeMillis();     }     return bufferMap.get(key);   }   /**    * create buffer map, allow overwrite    *    * @return    */   protected Map createBufferMap() {     return Collections.synchronizedMap(new HashMap());   } } 这里使用了 volatile、 synchronized 来支持多线程并发访问。也可以用单独一个线程,来更新数据 buffer 的。可能那样更好,也未可知。 使用起来也很简单,以下举一个例子,比如我们把配置参数保存在数据库中,运行时候可以读,如果直接读数据库,每次都需要运行 SQL. 而是用了上面的 cache ,则可以让读数据库减少到每分钟只读一次。 以下是定义一个自己的 cache 常量 applicationConfigBuffer (可以用 static),     static MemPeriodicLazyReloadCacheProvider applicationConfigBuffer = null;     PeriodicLazyReloadCache cache = null;     // appconfig cache     cache = new PeriodicLazyReloadCache() {       public long getReloadPeriodMillis() {         return DateUtils.MILLIS_PER_MINUTE;       }       public void reload(final Map bufferMap) {         log.info("reload appliction config data for cache....");                  DataSource ds = ...;         SqlRunnable run = new SqlRunnable() {           public void run(final Connection con) {             List dataList = xxx.getAll();             for (Object obj : dataList) {               ConfigData c = (ConfigData) obj;               bufferMap.put(c.getKeyCol(), c.getValueCol());             }           }         };         JdbcTransactionUtils.doWithJdbcTransactionDefaultCommit(run, ds);       }     };     applicationConfigBuffer = new MemPeriodicLazyReloadCacheProvider(cache);        真正用的时候,只有一行代码: Object obj = applicationConfigBuffer.get(key);   简单吧?以上 cache 不限于 J2EE 环境,也可以用于 Java 桌面程序中。

下载文档到电脑,查找使用更方便

文档的实际排版效果,会与网站的显示效果略有不同!!

需要 5 金币 [ 分享文档获得金币 ] 0 人已下载

下载文档