Java 使用MemoryCache缓存,缓存数据库主数据,提高数据读写性能
2017-07-25 00:00
661 查看
基于数据库的应用系统中,经常有必要根据 ID 获取编号或者名称,这是因为我们设计数据库,一般按照“三范式”来设计数据库,业务数据表中只存放主数据的 ID。而根据 ID 获取编号或者名称,通常是使用 SQL 实时查询。每次都查询数据库,数据库负荷不小,这部分其实可以优化。
常见的 cache , 包括 ehcache/oscache/apache jcs, 只适合于 cache 业务数据(transaction data),而不适合于 cache 主数据(master data)。还动不动就分布式缓存,其实没有必要。
这里的业务数据(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 , 包括 ehcache/oscache/apache jcs, 只适合于 cache 业务数据(transaction data),而不适合于 cache 主数据(master data)。还动不动就分布式缓存,其实没有必要。
这里的业务数据(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);
相关文章推荐
- OpenJDK源码研究笔记(五)-缓存Integer等类型的频繁使用的数据和对象,大幅度提升性能(一道经典的Java笔试题)
- OpenJDK源码研究笔记(五)-缓存Integer等类型的频繁使用的数据和对象,大幅度提升性能(一道经典的Java笔试题)
- Java - 使用JDBC操作数据库时,如何提升读取数据的性能?如何提升更新数据的性能?
- 关于使用Spring的缓存,将携带父id及所有子类全部数据获取,存入缓存,提高性能
- 【Java/Android性能优 4】PreloadDataCache支持预取的数据缓存,使用简单,支持多种缓存算法,支持不同网络类型,扩展性强
- 使用 SqlDependency 对象缓存数据以提高性能
- 【Java/Android性能优 4】PreloadDataCache支持预取的数据缓存,使用简单,支持多种缓存算法,支持不同网络类型,扩展性强
- java使用JDBC连接数据库,提高查询大量数据速度
- OpenJDK源码研究笔记(五)-缓存Integer等类型的频繁使用的数据和对象,大幅度提升性能(一道经典的Java笔试题)
- OpenJDK源码研究笔记(五)-缓存Integer等类型的频繁使用的数据和对象,大幅度提升性能(一道经典的Java笔试题)
- 以编程方式使用批语句节省 数据库IO来提高性能
- 通过缓存数据库结果提高PHP性能
- 利用Cache缓存数据提高大数据量访问性能
- 使用多结果集读取数据减少服务器往返,提高性能
- 使用Java程序从数据库中查询大量的数据时出现异常:java.lang.OutOfMemoryError: Java heap space
- [转]使用asp.net的缓存技术提高站点性能
- 使用索引和统计特性来提高数据库的查询性能(转)
- 使用多结果集读取数据减少服务器往返,提高性能
- 利用数据缓存机制提高智能设备应用程序的数据访问性能