import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.CollectionUtils;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.Pipeline;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
@Slf4j
public class CacheContext<K, T> {
// 占位符标志空数据
public static final String DEFALT_VALUE = "#";
private Jedis jedis;
// 查询id
private List<K> queryData;
// 未命中缓存id
private List<K> missData;
// 返回class
private Class<T> clazz;
// 通过返回类型获取获取查询key方法
private Function<T, K> getKeyFunction;
// 查询key转换成rediskey方法
private Function<K, String> keyMapping;
// 查询原数据方法
private Function<List<K>, List<T>> queryOriginFunction;
// redis缓存时间 单位秒
private int expireTime;
// 最后结果
private Map<K, T> res;
public CacheContext(Jedis jedis, List<K> queryData, Class<T> returnClass, int expireTime, Function<K, String> keyMapping, Function<T, K> getKeyFunction, Function<List<K>, List<T>> queryOriginFunction) {
this.jedis = jedis;
this.queryData = queryData;
this.keyMapping = keyMapping;
this.clazz = returnClass;
this.getKeyFunction = getKeyFunction;
this.queryOriginFunction = queryOriginFunction;
this.expireTime = expireTime;
missData = Lists.newArrayList();
res = Maps.newHashMap();
}
public void queryRedis() {
//得到redis查询key
String[] keys = queryData.stream().map(keyMapping).toArray(String[]::new);
List<String> values = jedis.mget(keys);
for (int i = 0; i < keys.length; i++) {
String s = values.get(i);
//未命中加入miss列表
if (s == null) missData.add(queryData.get(i));
// 说明数据库没有该记录
else if (s.equals(DEFALT_VALUE)) continue;
// 反序列化
else {
res.put(queryData.get(i), JSONObject.parseObject(s, clazz));
}
}
}
public Map<K, T> queryOrigin() {
Map<K, T> originMap = Maps.newHashMap();
// 没有miss 直接返回
if (CollectionUtils.isEmpty(missData)) {
return originMap;
}
// missData
List<T> list = queryOriginFunction.apply(missData);
list = list == null ? Lists.newArrayList() : list;
Map<K, T> originRes = list.stream().collect(Collectors.toMap(getKeyFunction, Function.identity(), (o1, o2) -> o1));
//查库没有的 也要用map记录下来 回填默认值
for (K missDatum : missData) {
T t = originRes.get(missDatum);
originMap.put(missDatum, t);
if (t != null) res.put(missDatum, t);
}
return originMap;
}
public void storeCache(Map<K, T> waitStore) {
if (CollectionUtils.isEmpty(waitStore)) return;
Pipeline pipelined = jedis.pipelined();
try {
for (Map.Entry<K, T> entry : waitStore.entrySet()) {
K key = entry.getKey();
T value = entry.getValue();
if (value == null) pipelined.setex(keyMapping.apply(key), expireTime, DEFALT_VALUE);
else pipelined.setex(keyMapping.apply(key), expireTime, JSONObject.toJSONString(value));
}
} catch (Exception e) {
log.error("[[title={}]],fail,waitStore = {}", "storeCache", JSONObject.toJSONString(waitStore));
} finally {
pipelined.sync();
}
}
public Map<K, T> getList() {
// redis查询
queryRedis();
// 源头查询
Map<K, T> originMap = queryOrigin();
// 回写redis
storeCache(originMap);
return res;
}
}
CacheContext
于 2023-02-16 11:08:55 首次发布