缓存方案
Redis和Memcached中选择Redis,因为Redis可通过一些匹配的原则找到对应的Key,而Memcached需要在上层应用自己设计匹配规则。
缓存对象(CacheObject )
public abstract class CacheObject implements Serializable {
private static final long serialVersionUID = 3752520699855146119L;
@Getter @Setter private Object id;
}
选择一:缓存操作者(CacheOperator)
基类CacheOperator
对于每一种缓存的类,都需要实现其子类。
获取Jedis
private Jedis getJedis() {
if (null == jedis) {
try {
ResourceBundle bundle = ResourceBundle.getBundle("cache");
JedisPoolConfig config = new JedisPoolConfig();
JedisPool pool = new JedisPool(config, bundle.getString("ip"), Integer.parseInt(bundle.getString("port")), 1000);
jedis = pool.getResource();
} catch (Exception e) {
return null;
}
}
return jedis;
}
这里采用Jedis作为Redis的连接器,ResourceBundle.getBundle
是常用的读取properties配置的方式。
// cache.properties
ip=127.0.0.1
port=6379
缓存的增删查改
/**
* 向缓存中增加实体
* @param key
* @param entity
*/
protected <T extends BaseEntity> void putEntity(String key, T entity) {
if (null != this.getJedis()) {
this.getJedis().set(key.getBytes(), JSON.toJSONBytes(entity));
} else {
logger.info("缓存服务连接失败,不能放入数据(" + entity.toString() + ")");
}
}
/**
* 向缓存中增加实体集合
* @param key
* @param entities
*/
protected <T extends BaseEntity> void putEntities(String key, List<T> entities) {
if (null != this.getJedis()) {
this.getJedis().set(key.getBytes(), JSON.toJSONBytes(entities));
}
}
/**
* 向缓存中增加缓存对象
* @param key
* @param cacheObject
*/
protected <T extends CacheObject> void putCacheObject(String key, T cacheObject) {
if (null != this.getJedis()) {
this.getJedis().set(key.getBytes(), JSON.toJSONBytes(cacheObject));
}
}
/**
* 从缓存中获取实体
* @param key
* @return
*/
protected <T extends BaseEntity> T getEntity(String key, Class<T> clazz) {
if (null != this.getJedis()) {
byte[] bytes = this.getJedis().get(key.getBytes());
if (null == bytes) {
return null;
}
return JSON.parseObject(bytes, clazz);
}
return null;
}
/**
* 从缓存中获取缓存对象
* @param key
* @param clazz
* @return
*/
protected <T extends CacheObject> T getCacheObject(String key, Class<T> clazz) {
if (null != this.getJedis()) {
byte[] bytes = this.getJedis().get(key.getBytes());
if (null == bytes) {
return null;
}
return JSON.parseObject(bytes, clazz);
}
return null;
}
/**
* 从缓存中获取实体集合
* @param key
* @param clazz
* @return
*/
protected <T extends BaseEntity> List<T> getEntities(String key, Class<T> clazz) {
try {
if (null != this.getJedis()) {
byte[] bytes = this.getJedis().get(key.getBytes());
if (null == bytes) {
return null;
}
return JSON.parseArray(new String(bytes, "UTF-8"), clazz);
}
} catch (UnsupportedEncodingException ex) {
ex.printStackTrace();
}
return null;
}
/**
* 从缓存中删除实体/实体集合,缓存对象
* @param key
*/
protected void delete(String key) {
if (null != this.getJedis()) {
this.getJedis().del(key.getBytes());
}
}
/**
* 根据Key前缀获取对应的所有实体
* @param keyPrefix
* @param clazz
* @return
*/
protected <T extends BaseEntity> List<T> getEntitiesByKeyPrefix(String keyPrefix, Class<T> clazz) {
if (null != this.getJedis()) {
Set<byte[]> keySet = this.getJedis().keys((keyPrefix + "*").getBytes());
if (keySet.size() == 0) {
return null;
}
T t;
List<T> result = new ArrayList<>();
List<byte[]> list = this.getJedis().mget(keySet.toArray(new byte[1][keySet.size()]));
for (byte[] bytes : list) {
t = JSON.parseObject(bytes, clazz);
result.add(t);
}
return result;
}
return null;
}
/**
* 根据Key前缀获取对应的所有缓存对象
* @param keyPrefix
* @param clazz
* @return
*/
protected <T extends CacheObject> List<T> getCacheObjectsByKeyPrefix(String keyPrefix, Class<T> clazz) {
if (null != this.getJedis()) {
Set<byte[]> keySet = this.getJedis().keys(
(keyPrefix + "*").getBytes());
List<byte[]> list = this.getJedis().mget(
keySet.toArray(new byte[1][keySet.size()]));
List<T> result = new ArrayList<T>();
T t;
for (byte[] bytes : list) {
t = JSON.parseObject(bytes, clazz);
result.add(t);
}
return result;
}
return null;
}
注:
(1)所有的put和get操作,都分为CacheObject
和BaseEntity
两种,一种是拿到缓存对象,一种是拿到Entity对象,基本上一致。
缓存操作者的子类(需要缓存的类对应)
/**
* 向缓存中增加DealCategory
* @param dealCategory
*/
public void putDealCategory(DealCategory dealCategory) {
super.putEntity("DealCategory." + dealCategory.getId(), dealCategory);
// 维护其父类别的子类别缓存
List<DealCategory> subCategories = getSubCategories(dealCategory.getParentId());
if (subCategories != null && subCategories.size() > 0) {
if (subCategories.contains(dealCategory)) {
int index = 0;
for (int i = 0; i < subCategories.size(); i++) {
if (subCategories.get(i).getId() == dealCategory.getId()) {
index = i;
}
}
subCategories.remove(index);
}
subCategories.add(dealCategory);
putSubCategories(dealCategory.getParentId(), subCategories);
}
}
注:
(1)put的时候,参数只有DealCategory
,根据类名.+具体的ID
(一定的规则)当Key,把dealCategory
放入缓存中。
(2)put和delete时,需要判断缓存对象的父节点的子节点们
缓存,需要更新就更新,需要删除就删除。
选择二:缓存工具(CacheUtil)
使用Util的静态方法进行缓存的操作,相比上面的Operator类来说,少了子类的重写和类初始化的操作(采用静态方法)。
获取Jedis对象
同上
生成Key
private static String generateKey(Class clazz, Object id) {
return clazz.getName() + "." + id;
}
根据类名+id
生成Key。
存入缓存
/**
* 向缓存中增加实体
* @param key
* @param entity
*/
public static <T extends BaseEntity> void putEntity(String key, T entity) {
if (null != getJedis()) {
getJedis().set(key.getBytes(), JSON.toJSONBytes(entity));
} else {
logger.info("缓存服务连接失败,不能放入数据(" + entity.toString() + ")");
}
}
public static <T extends BaseEntity> void putEntity(T entity) {
if (null != getJedis()) {
String key = generateKey(entity.getClass(), entity.getId());
getJedis().set(key.getBytes(), JSON.toJSONBytes(entity));
} else {
logger.info("缓存服务连接失败,不能放入数据(" + entity.toString() + ")");
}
}
在外部可以直接调用该静态方法,两种参数模式,一种是自带Key,一种不自带Key只有entity,那么需要调用上面的生成Key的方法,但要注意在整个工程中,需要保持key的规则一致。