当前位置:网站首页>redis 缓存设置,实现类似putIfAbsent功能
redis 缓存设置,实现类似putIfAbsent功能
2022-07-24 10:40:00 【太极剑奥义】
缓存查询为空
在使用缓存过程中,我们都会面临没有查询到数据的情况,然后再把结果查询结果设置到缓存中,这样的场景有很多
常规实现
我们先用普通的方法来实现一下
- 缓存列表
private List<InfoCategory> queryAllCategory(String tid) {
String key = String.format(Constants.ALL_CATEGORY,tid);
String value = redisTemplate.opsForValue().get(key);
if(!StringUtils.isEmpty(value)){
return JSON.parseArray(value,InfoCategory.class);
}else{
List<InfoCategory> list = new LambdaQueryChainWrapper<>(categoryMapper)
.eq(InfoCategory::getTid, tid)
.list();
if(!CollectionUtils.isEmpty(list)){
redisTemplate.opsForValue().set(key, JSON.toJSONString(list));
}
return list;
}
}
- 缓存普通对象
public CategoryEventListResponse queryEventName(String tid, String appletId, String eventName, String taskSerial) {
String key = String.format(Constants.EVENT_TASK_NAME,tid,appletId,eventName,taskSerial);
String value = redisTemplate.opsForValue().get(key);
if(!StringUtils.isEmpty(value)){
return JSON.parseObject(value,CategoryEventListResponse.class);
}else{
CategoryEventListResponse response =doQueryEventName(tid, appletId, eventName, taskSerial);
if(Objects.isNull(response)){
response = new CategoryEventListResponse();
}
redisTemplate.opsForValue().set(key, JSON.toJSONString(response),2*60, TimeUnit.SECONDS);
return response;
}
}
缺点:很多相似的功能基本上都如同上面的代码实现,比较繁琐、累赘,代码复用性不强
优化方案
1、在获取缓存的时候,直接把一个回调方法传过去,在没有数据的情况下可以直接运行回调方法缓存值
2、需要封装的查询,回调方法全部统一封装,调用者甚至感觉不到存在回调方法
直接上最终版代码
封装redisTemplate
@Component
@Data
@Slf4j
public class CallBackRedisTemplate {
@Autowired
private RedisTemplate<String,String> redisTemplate;
/** * * @param key redis key * @param callable callable function * @param vClass return type class * @param defaultValue when callable function get null,set defaultValue to avoid to call function again,storage like {} [] * @param timeUnit * @param time * @param <V> * @return */
public <V> V get(String key, Callable<V> callable,Class<V> vClass,V defaultValue, TimeUnit timeUnit,Long time) {
String redisValue = redisTemplate.opsForValue().get(key);
if(StringUtils.isEmpty(redisValue)){
try {
V v = callable.call();
if(Objects.isNull(v)){
redisTemplate.opsForValue().set(key,JSON.toJSONString(defaultValue),time,timeUnit);
return defaultValue;
}else{
redisTemplate.opsForValue().set(key,JSON.toJSONString(v),time,timeUnit);
return v;
}
} catch (Exception e) {
e.printStackTrace();
log.error("callable error key={}",key,e);
return null;
}
}
return JSON.parseObject(redisValue,vClass);
}
/** * * @param key redis key * @param callable callable function * @param vClass return type class * @param timeUnit * @param time * @param <V> * @return */
public <V> V get(String key, Callable<V> callable,Class<V> vClass, TimeUnit timeUnit,Long time) {
String redisValue = redisTemplate.opsForValue().get(key);
if(StringUtils.isEmpty(redisValue)){
try {
V v = callable.call();
if (!Objects.isNull(v)) {
redisTemplate.opsForValue().set(key, JSON.toJSONString(v), time, timeUnit);
}
return v;
} catch (Exception e) {
e.printStackTrace();
log.error("callable error key={}",key,e);
return null;
}
}
return JSON.parseObject(redisValue,vClass);
}
/** * * @param key redis key * @param callable callable function * @param typeReference return reference type class * @param defaultValue when callable function get null,set defaultValue to avoid to call function again,storage like {} [] * @param timeUnit * @param time * @param <V> * @return */
public <V> V get(String key, Callable<V> callable,TypeReference<V> typeReference,V defaultValue, TimeUnit timeUnit,Long time) {
String redisValue = redisTemplate.opsForValue().get(key);
if(StringUtils.isEmpty(redisValue)){
try {
V v = callable.call();
if(Objects.isNull(v)){
redisTemplate.opsForValue().set(key,JSON.toJSONString(defaultValue),time,timeUnit);
return defaultValue;
}else{
redisTemplate.opsForValue().set(key,JSON.toJSONString(v),time,timeUnit);
return v;
}
} catch (Exception e) {
e.printStackTrace();
log.error("callable error key={}",key,e);
return null;
}
}
return JSON.parseObject(redisValue,typeReference);
}
/** * * @param key redis key * @param callable callable function * @param typeReference return reference type class * @param timeUnit * @param time * @param <V> * @return */
public <V> V get(String key, Callable<V> callable,TypeReference<V> typeReference, TimeUnit timeUnit,Long time) {
String redisValue = redisTemplate.opsForValue().get(key);
if(StringUtils.isEmpty(redisValue)){
try {
V v = callable.call();
if (!Objects.isNull(v)) {
redisTemplate.opsForValue().set(key, JSON.toJSONString(v), time, timeUnit);
}
return v;
} catch (Exception e) {
e.printStackTrace();
log.error("callable error key={}",key,e);
return null;
}
}
return JSON.parseObject(redisValue,typeReference);
}
}
- 反序列化处理
这里有一个点,就是回调方法返回的是一个泛型V,在fastJson反序列化的时候,需要确定V的calss类型,所以添加了参数 Class<V> vClass 。当返回值为列表形式的时候,我们在使用反序列化就需要使用到 TypeReference<V> typeReference
- 在回调过程中没有值,下次不希望再来调用回调方法,减少对数据库的压力
添加参数 V defaultValue ,给缓存系统直接设置到缓存服务中,避免对数据库或者服务造成压力
封装业务service
- EventBizCacheService
public interface EventBizCacheService {
/** * cache all category * @param tid * @return */
List<InfoCategory> queryAllCategory(String tid);
/** * cache all event name * @param tid * @return */
CategoryEventListResponse queryEventName(String tid, String appletId, String eventName, String taskSerial);
}
- impl
@Service
public class EventBizCacheServiceImpl implements EventBizCacheService {
@Autowired
private CallBackRedisTemplate callBackRedisTemplate;
@Autowired
private InfoCategoryMapper categoryMapper;
@Autowired
private InfoCategoryEventRelMapper relMapper;
@Autowired
private InfoTenantAppletEventMapper eventMapper;
@Autowired
private InfoEventTaskMapper taskMapper;
@Autowired
private CrowCategoryService crowCategoryService;
@Override
public List<InfoCategory> queryAllCategory(String tid) {
String key = String.format(Constants.ALL_CATEGORY,tid);
return callBackRedisTemplate.get(key,
() -> new LambdaQueryChainWrapper<>(categoryMapper).eq(InfoCategory::getTid, tid).list(),
new TypeReference<List<InfoCategory>>(){
},
TimeUnit.DAYS,
360L);
}
@Override
public CategoryEventListResponse queryEventName(String tid, String appletId, String eventName, String taskSerial) {
String key = String.format(Constants.EVENT_TASK_NAME,tid,appletId,eventName,taskSerial);
return callBackRedisTemplate.get(key,
()->{
CategoryEventListResponse cResult = crowCategoryService.queryEventName(appletId, eventName, taskSerial);
if (cResult != null) {
return cResult;
}
return categoryMapper.queryEventName(appletId, eventName, taskSerial);
},
CategoryEventListResponse.class,
TimeUnit.DAYS,
360L);
}
}
这个业务类就是为了屏蔽callable方法,时调用者无需关系数据来源
总结
在业务开发过程中遇到代码实现差不多,只有部分业务功能不一样的时候,考虑通用方案来解决,把业务方法传递过去,让调用者通过lambda方法自己完成业务方法。
如果有更好的方法,还请大家不吝赐教。
边栏推荐
- [dish of learning notes dog learning C] detailed operator
- Erlang learning 02
- [dish of learning notes dog learning C] initial level of structure
- [correcting Hongming] what? I forgot to take the "math required course"!
- MySQL - 更新表中的数据记录
- Problem solving -- question 283 of leetcode question bank
- Kotlin domain specific language (DSL)
- Domain Driven practice summary (basic theory summary and analysis + Architecture Analysis and code design + specific application design analysis V) [easy to understand]
- [electronic device note 4] inductance parameters and type selection
- cookie sessionStorage localStorage 区别
猜你喜欢

MySQL - multi column index

Web Security Foundation - file upload (file upload bypass)

Will not be rejected! Learn the distributed architecture notes sorted out by Alibaba Daniel in 35 days, with a salary increase of 20K

Record AP and map calculation examples

Zoj1137+ operation 1 -- May 28, 2022

Create a vertical seekbar from scratch

PC Museum (2) 1972 hp-9830a

Qt应用程序防止多开,即单例运行

CMS vulnerability recurrence - ultra vires vulnerability

ZOJ 2770 differential restraint system -- 2 -- May 20, 2022
随机推荐
Binary search method
Machine learning quiz (10) using QT and tensorflow to create cnn/fnn test environment
Erlang学习01
Scope usage in POM file dependency
机器学习小试(10)使用Qt与Tensorflow创建CNN/FNN测试环境
Daily three questions 7.22
Simply use golang SQLC to generate MySQL query code
机器学习小试(11)验证码识别测试-使用Qt与Tensorflow2进行深度学习实验
MySQL - update data records in tables
Google Earth engine - QA in Landsat 5 toa dataset_ Pixel and QA_ Radsat band
New:Bryntum Grid 5.1.0 Crack
MySQL - unique index
PC博物馆(1) 1970年 Datapoint 2000
App automation and simple environment construction
Mina framework introduction "suggestions collection"
Nirvana rebirth! Byte Daniel recommends a large distributed manual, and the Phoenix architecture makes you become a God in fire
Binlog and iptables prevent nmap scanning, xtrabackup full + incremental backup, and the relationship between redlog and binlog
Erlang learning 01
[dish of learning notes dog learning C] advanced pointer
PC博物馆(2) 1972年 HP-9830A