当前位置:网站首页>Redis CacheClient
Redis CacheClient
2022-06-27 14:34:00 【Close your heart】
This tool solves Redis Cache breakdown of 、 Cache penetration 、 Caching avalanches , For more information, refer to generics and Function Use ! A very good way !
Be careful , The following code depends on Hutool tool kit , And references to several character constants , Change to any character by yourself !
Introduce :
Cache breakdown queryWithPassThrough
Cache penetration queryWithMutex
Cache avalanche queryWithLogicalExpireimport cn.hutool.core.util.BooleanUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
@Slf4j
@Component // register as IOC Container of Bean, Use direct Autowired
public class CacheClient {
private final StringRedisTemplate stringRedisTemplate;
// Define a thread pool , It is convenient to open threads to perform operations
private static final ExecutorService CACHE_REBUILD_EXECUTOR = Executors.newFixedThreadPool(10);
public CacheClient(StringRedisTemplate stringRedisTemplate) {
this.stringRedisTemplate = stringRedisTemplate;
}
// Add one String Key value pairs of type
public void set(String key, Object value, Long time, TimeUnit unit) {
stringRedisTemplate.opsForValue().set(key, JSONUtil.toJsonStr(value), time, unit);
}
// Set logical expiration Key, To avoid cache breakdown
public void setWithLogicalExpire(String key, Object value, Long time, TimeUnit unit) {
// Set logical expiration
HashMap<String, Object> hashMap = new HashMap();
hashMap.put("data", value);
hashMap.put("expireTime", LocalDateTime.now().plusSeconds(unit.toSeconds(time)));
// write in Redis
stringRedisTemplate.opsForValue().set(key, JSONUtil.toJsonStr(hashMap));
/**
RedisData redisData = new RedisData();
//redisData.setData(value);
//redisData.setExpireTime();
// write in Redis
stringRedisTemplate.opsForValue().set(key, JSONUtil.toJsonStr(redisData));
**/
}
// Cache penetration solution : Normal query , Walk normally . If DB No data , Insert with TTL Null value of
public <R, ID> R queryWithPassThrough(
String keyPrefix, ID id, Class<R> type, Function<ID, R> dbFallback, Long time, TimeUnit unit) {
String key = keyPrefix + id;
// 1. from redis Query store cache
String json = stringRedisTemplate.opsForValue().get(key);
// 2. Judge whether it exists
if (StrUtil.isNotBlank(json)) {
// 3. There is , Go straight back to
return JSONUtil.toBean(json, type);
}
// Determine whether the hit is null
if (json != null) {
// Return an error message
return null;
}
// 4. non-existent , according to id Query the database
R r = dbFallback.apply(id);
// 5. non-existent , Returns an error
if (r == null) {
// Write null values to redis
stringRedisTemplate.opsForValue().set(key, "", 5, TimeUnit.MINUTES);
// Return error message
return null;
}
// 6. There is , write in redis
this.set(key, r, time, unit);
return r;
}
// Cache avalanche solution : Query logic expired , If it's out of date , Then reinsert it
public <R, ID> R queryWithLogicalExpire(
String keyPrefix, ID id, Class<R> type, Function<ID, R> dbFallback, Long time, TimeUnit unit) {
String key = keyPrefix + id;
// 1. from redis Query store cache
String json = stringRedisTemplate.opsForValue().get(key);
// 2. Judge whether it exists
if (StrUtil.isBlank(json)) {
// 3. There is , Go straight back to
return null;
}
// 4. hit , Need first json Deserialize to object
HashMap<String,Object> hashMap = JSONUtil.toBean(json, HashMap.class);
R r = JSONUtil.toBean((JSONObject) hashMap.get("data"), type);
/**
RedisData redisData = JSONUtil.toBean(json, RedisData.class);
R r = JSONUtil.toBean((JSONObject) redisData.getData(), type);
LocalDateTime expireTime = redisData.getExpireTime();
**/
LocalDateTime localDateTime = LocalDateTime.parse((CharSequence) hashMap.get("expireTime"), DateTimeFormatter.ofPattern("yyyy-MM-dd E HH:mm:ss"));
// 5. Judge whether it is overdue , Using pure JDK Tools for
if (localDateTime.isAfter(LocalDateTime.now())) {
// 5.1. Not expired , Directly return the store information
return r;
}
// 5.2. Has expired , Cache rebuild required
// 6. Cache rebuild
// 6.1. Get mutex
String lockKey = "LOCK_SHOP_KEY" + id;
boolean isLock = tryLock(lockKey);
// 6.2. Judge whether the lock is obtained successfully
if (isLock) {
// 6.3. success , Turn on independent threads , Realize cache reconstruction
CACHE_REBUILD_EXECUTOR.submit(() -> {
try {
// Query the database
R newR = dbFallback.apply(id);
// Rebuild cache
this.setWithLogicalExpire(key, newR, time, unit);
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
// Release the lock
unlock(lockKey);
}
});
}
// 6.4. Return expired shop information
return r;
}
// Cache avalanche solution : The mutex : I will call myself , If Key non-existent , Then only one thread performs the insertion DB operation
public <R, ID> R queryWithMutex(
String keyPrefix, ID id, Class<R> type, Function<ID, R> dbFallback, Long time, TimeUnit unit) {
String key = keyPrefix + id;
// 1. from redis Query store cache
String shopJson = stringRedisTemplate.opsForValue().get(key);
// 2. Judge whether it exists
if (StrUtil.isNotBlank(shopJson)) {
// 3. There is , Go straight back to
return JSONUtil.toBean(shopJson, type);
}
// Determine whether the hit is null
if (shopJson != null) {
// Return an error message
return null;
}
// 4. Realize cache reconstruction
// 4.1. Get mutex
String lockKey = "Operate:AddLock" + id;
R r = null;
try {
boolean isLock = tryLock(lockKey);
// 4.2. Judge if you are successful
if (!isLock) {
// 4.3. Lock acquisition failed , Hibernate and try again
Thread.sleep(50);
return queryWithMutex(keyPrefix, id, type, dbFallback, time, unit);
}
// 4.4. Lock acquired successfully , according to id Query the database
r = dbFallback.apply(id);
// 5. non-existent , Returns an error
if (r == null) {
// Write null values to redis
stringRedisTemplate.opsForValue().set(key, "", 5, TimeUnit.MINUTES);
// Return error message
return null;
}
// 6. There is , write in redis
this.set(key, r, time, unit);
} catch (InterruptedException e) {
throw new RuntimeException(e);
} finally {
// 7. Release the lock
unlock(lockKey);
}
// 8. return
return r;
}
// Try to lock
private boolean tryLock(String key) {
Boolean flag = stringRedisTemplate.opsForValue().setIfAbsent(key, "1", 10, TimeUnit.SECONDS);
return BooleanUtil.isTrue(flag);
}
// Unlock
private void unlock(String key) {
stringRedisTemplate.delete(key);
}
}Special instructions : The above article , It's all my actual operation , Written notes , Won't steal other people's articles ! Please , Do not directly embezzle ! Reprint remember to mark the source !
边栏推荐
- [OS command injection] common OS command execution functions and OS command injection utilization examples and range experiments - based on DVWA range
- 【业务安全03】密码找回业务安全以及接口参数账号修改实例(基于metinfov4.0平台)
- How to select cross-border e-commerce multi merchant system
- The second part of the travel notes of C (Part II) structural thinking: Zen is stable; all four advocate structure
- ThreadLocal之强、弱、软、虚引用
- QT 如何在背景图中将部分区域设置为透明
- [an Xun cup 2019]attack
- élégant pool de threadpoolexecutor personnalisé
- ThreadLocal之强、弱、軟、虛引用
- Design skills of main function of Blue Bridge Cup single chip microcomputer
猜你喜欢

海量数据!秒级分析!Flink+Doris构建实时数仓方案

AQS抽象队列同步器

Learning records of numpy Library

Great God developed the new H5 version of arXiv, saying goodbye to formula typography errors in one step, and the mobile phone can easily read literature

Acwing game 57

Pytorch learning 3 (test training model)

直播app运营模式有哪几种,我们该选择什么样的模式?

国产数据库乱象

清华&商汤&上海AI&CUHK提出Siamese Image Modeling,兼具linear probing和密集预测性能!...

Pytoch learning 2 (CNN)
随机推荐
Kyndryl partnered with Oracle and Veritas
【业务安全03】密码找回业务安全以及接口参数账号修改实例(基于metinfov4.0平台)
ThreadLocal之强、弱、軟、虛引用
初识云原生安全:云时代的最佳保障
巧用redis实现点赞功能,它不比mysql香吗?
[business security-02] business data security test and example of commodity order quantity tampering
Multithreading Basics (III)
AQS Abstract queue synchronizer
Daily 3 questions (1): find the nearest point with the same X or Y coordinate
Why must Oracle cloud customers self test after the release of Oracle cloud quarterly update?
Professor huangxutao, a great master in CV field, was born at the age of 86. UIUC specially set up a doctoral scholarship to encourage cutting-edge students
Great God developed the new H5 version of arXiv, saying goodbye to formula typography errors in one step, and the mobile phone can easily read literature
Overseas warehouse knowledge popularization
AQS抽象队列同步器
【OS命令注入】常见OS命令执行函数以及OS命令注入利用实例以及靶场实验—基于DVWA靶场
海外仓知识科普
What if the win system cannot complete the update and is revoking the status change
What kind of experience is it to read other people's code
Calcul de la confidentialité Fate - Prévisions hors ligne
Buuctf Misc