当前位置:网站首页>Redis cache settings, similar to putifabsent function
Redis cache settings, similar to putifabsent function
2022-07-24 10:41:00 【The profound meaning of Tai Chi Sword】
Cache query is empty
In the process of using cache , We will all face the situation that no data can be queried , Then set the result of the query to the cache , There are many such scenes
Regular implementation
Let's use ordinary methods to realize
- Cache list
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;
}
}
- Cache ordinary objects
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;
}
}
shortcoming : Many similar functions are basically implemented as the above code , More complicated 、 Cumbersome , Code reusability is not strong
Optimization plan
1、 When getting the cache , Pass a callback method directly , When there is no data, you can directly run the callback method to cache values
2、 Queries that need encapsulation , Callback methods are all encapsulated , The caller doesn't even feel that there is a callback method
Directly on the final version of the code
encapsulation 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);
}
}
- Deserialization processing
Here's a point , The callback method returns a generic V, stay fastJson When deserializing , You need to determine V Of calss type , So we added parameters Class<V> vClass . When the return value is in list form , When using deserialization, we need to use TypeReference<V> typeReference
- There is no value during the callback , I don't want to call the callback method again next time , Reduce the pressure on the database
Add parameter V defaultValue , Set the cache system directly into the cache service , Avoid putting pressure on databases or services
Packaging business 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);
}
}
This business class is for shielding callable Method , The caller does not need to be related to the data source
summary
In the process of business development, the code implementation is almost , Only when some business functions are different , Consider general solutions to solve , Pass on the business method , Let the caller go through lambda Methods complete the business method by yourself .
If there is a better way , Please give me your advice .
边栏推荐
- MySQL - 唯一索引
- Sentinel flow control quick start
- Onpropertychange event "suggestions collection"
- Tidb query SQL report runtime error: index out of range [-1] error
- 《nlp入门+实战:第二章:pytorch的入门使用 》
- 火山引擎:开放字节跳动同款AI基建,一套系统解决多重训练任务
- js函数调用下载文件链接
- 划分数据2
- [dish of learning notes dog learning C] evaluation expression
- CMS vulnerability recurrence - ultra vires vulnerability
猜你喜欢

Five best WordPress advertising plug-ins

Machine learning quiz (11) verification code recognition test - deep learning experiment using QT and tensorflow2

Sentinel 实现 pull 模式规则持久化

Qt程序最小化托盘后,再弹出个msgbox,点击确定后程序退出问题解决

NiO knowledge points

Arduino + AD9833 waveform generator

图像处理:RGB565转RGB888

MySQL - 唯一索引

N-tree, page_ Size, database strict mode modification, and the difference between delete and drop in the database
![[electronic device note 3] capacitance parameters and type selection](/img/d2/1ddb309a8f3cfe5f65c71964052006.png)
[electronic device note 3] capacitance parameters and type selection
随机推荐
数组元素移除问题
MySQL - 更新表中的数据记录
Qt创建应用程序托盘及相关功能
How many indexes are associated indexes under MySQL InnoDB?
When to use obj['attribute name'] for the attribute name of an object
Onpropertychange event "suggestions collection"
图像处理:RGB565转RGB888
Image processing: floating point number to fixed point number
[dish of learning notes dog learning C] initial level of pointer
Google Earth engine - QA in Landsat 5 toa dataset_ Pixel and QA_ Radsat band
[dish of learning notes dog learning C] advanced pointer
Sentinel 三种流控模式
Sentinel 三种流控效果
每日三题 7.22
After the QT program minimizes the tray, a msgbox pops up. Click OK and the program exits. The problem is solved
[AHK] AutoHotKey tutorial ①
火山引擎:开放字节跳动同款AI基建,一套系统解决多重训练任务
MySQL - 索引的隐藏和删除
MySQL - 删除数据库表中的数据
Mina framework introduction "suggestions collection"