当前位置:网站首页>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 !
边栏推荐
- Why must Oracle cloud customers self test after the release of Oracle cloud quarterly update?
- Handling methods for NVIDIA deepstream running delay, jamming and crash
- Sword finger offer II 039 Histogram maximum rectangular area monotonic stack
- Acwing game 57
- Dynamic Networks and Conditional Computation论文简读和代码合集
- 原子操作类
- 解析Activity启动-生命周期角度
- 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
- 国产数据库乱象
- 注解学习总结
猜你喜欢

原子操作类

Calcul de la confidentialité Fate - Prévisions hors ligne

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

Naacl 2022 | TAMT: search the transportable Bert subnet through downstream task independent mask training

请求一下子太多了,数据库危

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

Interpretation of new version features of PostgreSQL 15 (including live Q & A and PPT data summary)

Strong, weak, soft and virtual references of ThreadLocal

Acwing game 57

【业务安全-04】万能用户名及万能密码实验
随机推荐
522. 最长特殊序列 II / 剑指 Offer II 101. 分割等和子集
[advanced mathematics] from normal vector to surface integral of the second kind
AQS抽象队列同步器
剑指 Offer II 039. 直方图最大矩形面积 单调栈
Pychart installation and setup
CV领域一代宗师黄煦涛教授86岁冥诞,UIUC专设博士奖学金激励新锐
直播app运营模式有哪几种,我们该选择什么样的模式?
CAS之比较并交换
OpenSSF安全计划:SBOM将驱动软件供应链安全
Library management system
Reflection learning summary
初识云原生安全:云时代的最佳保障
External memory
SFINAE
Brief reading of dynamic networks and conditional computing papers and code collection
Pytoch learning 2 (CNN)
Redis CacheClient
Leetcode 724. 寻找数组的中心下标(可以,一次过)
【业务安全-01】业务安全概述及测试流程
[daily 3 questions (3)] maximum number of balls in the box