使用方式及代码
//查询 某条记录表名 ts = 表名Cache.getValue(表名Cache.getEndkey(), datatype + "_" + number);
//清除缓存
表名Cache.delete(null, 表名Cache.cacheName(ts));
//分页查询
List<Object> list = null;
if ("desc".equals(sort)){
list = productonuserCache.userQueryBySort(productonuserCache.getEndkey(), userId, 1 , page, size);
}else{
list = productonuserCache.userQueryBySort(productonuserCache.getEndkey(), userId, 0 , page, size);
}
Long total = productonuserCache.getTotal(productonuserCache.getEndkey(),userId);
// 每张表需要多个字段查询的时候,需要实现多个 缓存类。
例如。 表名字段名Cache
@Override
public String cacheName(表名 v) {
return v.getDatatype()+"_"+v.get字段名();
}
——————
1、利用泛型及抽象类,使用者来实现主要的数据加载部分方法。
好处是,用户简单实现无逻辑,不容易出错。
public abstract class CacheTools<V> {
/**
* 加载数据
* @param userId
* @return
*/
public abstract List<V> getAllData(String userId);
/**
* 排序字段
* @param v
* @return
*/
public abstract double getScore(V v) ;
/**
* redis key 的组成 hash 集合存放的主键。例如: 订单,就是 ordercode
* @param v
* @return
*/
public abstract String cacheName(V v);
public abstract V findDbOne(String key, String userId);
/**
* 缓存名称,一般使用表名
* @return
*/
public abstract String getEndkey();
}
2、更新缓存
/**
* 添加或更新
* @param tmp
* @return
*/
public V save(String userId,V v) {
if (v == null){
log.error("{m:CacheTools.save,msg: v==null}---");
return v;
}else{
String key = getEndkey();
String endkey = joinKey(key, userId);
modifiedCount(endkey);
ZSetOperations<String, String> zset = getRedisService().getZsetOper();
return saveOne(endkey, zset, v);
}
}
/**
* 批量添加或更新 不能用于加载。
* @param userId
* @param tmp
* @return
*/
public Iterable<V> save(String userId, Iterable<V> tmp) {
log.info(" {Cachetools save }: "+userId + tmp);
ZSetOperations<String, String> zset = getRedisService().getZsetOper();
tmp.forEach((V v)->{
saveOne(joinKey(getEndkey(), userId), zset, v);
});
return tmp;
}
3、删除缓存
public void delete(String userId, Object... values){
log.info("{cacheTools}:delete"+userId + values);
String key = getEndkey();
String endkey = joinKey(key, userId);
modifiedCount(endkey);
log.info("-------------CacheTools: delete: "+joinHashKey(endkey)+ " values"+values);
getRedisService().hremoveKey(joinHashKey(endkey), values);
if(loadSortFlag){
log.info("{ cache tools } delete :"+values + " "+userId);
ZSetOperations<String, String> zset = getRedisService().getZsetOper();
zset.remove(joinZsetKey(endkey), values);
}
}
4、精确定位查询
public V getCacheValue(String key,String userId ,String cachename, RedisService rs){
V val = (V)rs.hget(joinHashKey(joinKey(key, userId)), cachename);
if (val == null){
// 2019 03 05 解决,只想加载当前查询内容的情况。不考虑多加载,也不考虑用户纬度。
if (onlyLoadCurrentFlag){
val = findDbOne(cachename,userId);
save(userId, val);
}else{
if (enabledLoad( key, userId, rs )){
val = (V)rs.hget(joinHashKey(joinKey(key, userId)), cachename);
log.info(" 阻塞加载后获取内容:"+key + " "+ userId+" "+val);
return val;
};
}
}
return val;
}
5、查询总数
/**
* 查询数据总数
* @param string
* @param userId
* @return
*/
public Long getTotal(String key, String userId) {
ZSetOperations<String, String> zset = getRedisService().getZsetOper();
return zset.size(joinZsetKey(joinKey(key,userId)));
}
6、分页查询实现
/**
* 倒序分页查询,用户自己内容,这个部分属于活跃的占少数,所以采用不欲缓存, 并且采用加失效时间。
* @param userId
* @param sort 1 倒序
* @param page
* @param size
* @return
*/
public List<Object> userQueryBySort(String key ,String userId,int sort , int page, int size) {
log.info("{cache}:userQueryBySort"+key+userId);
//维护用户活跃度
refreshUser(userId);
List <Object> list = query(sort, page, size, joinKey(key, userId));
if (list == null || list.size() <=0 ){
log.info("{缓存未查询到内容}"+userId + " "+ key);
if (enabledLoad( key, userId, getRedisService() )){
list = query(sort, page, size, joinKey(key, userId));
log.info("querybysort- 阻塞加载后获取内容:"+key + " "+ userId+" "+list);
return list;
}
}else{
log.info("query by sort {缓存被发现:}"+list.size());
}
return list;
}
/**
* 分页查询
* @param key
* @param sort 1 倒序
* @param page
* @param size
* @return
*/
public List<Object> queryBySort(String key , int sort ,int page, int size) {
return query(sort, page, size, key);
}
private List<Object> query(int sort, int page, int size, String endkey) {
log.info("{cache}:query"+endkey);
page = page <= 0 ? 1:page;
ZSetOperations<String, String> zset = getRedisService().getZsetOper();
Set <String> keys = null;
if (1 == sort){
keys = zset.reverseRange(joinZsetKey(endkey), ( page - 1 ) * size, page * size - 1);
}else{
keys = zset.range(joinZsetKey(endkey), ( page - 1 ) * size, page * size - 1);
}
log.info("query:size :"+keys.size());
List tmp = getRedisService().hmget(joinHashKey(endkey), keys);
log.info("query:list"+tmp.size());
return tmp;
}
7、实现方式
组件使用方式
import com.mini.openec.utils.CacheTools;
@Service
public class 表名Cache extends CacheTools<表名>{
private final Log log = LogFactory.getLog(表名Cache.class);
public 表名Cache() {
/* 参数说明,
boolean loadActiveUserFlag,
= true 自动缓存 10天内活跃用户的本表内容
= false 自动缓存 表的全部数据,如果无此需求,只要在getAllData 方法返回null 即可不自动缓存全部内容
boolean loadSortFlag ,
= true 生成分页缓存,可以分页查询
= false 不生成分页缓存,不能分页查询
boolean onlyLoadCurrentFlag
= true 只加载当前内容,如与用户无关,userId 传null
= false 按前两个参数加载。
*/
init(false, false, true); // 只缓存当前值
}
@Override
public String cacheName(表名 v) {
return v.getDatatype()+"_"+v.getNumber();
}
@Override
public List<表名> getAllData(String userId) {
return null;//表名Service.listAll();
}
@Override
public double getScore(表名 v) {
return v.getCode().hashCode();
}
@Override
public String getEndkey() {
return "表名";
}
@Override
public 表名 findDbOne(String key,String userId) {
if (StringUtils.isNotEmpty(key)){
String strs[] = key.split("_");
if (strs.length >= 2){
log.info("{key:"+strs[1]+",old:"+key+"}");
return 表名Service.findByNumber(strs[1]);
}
}
return null;
}
}