使用 Redis 查询的一般程序实现和击穿、雪崩、穿透
Jihongchang(讨论 | 贡献)2023年2月13日 (一) 08:02的版本
https://www.bilibili.com/video/BV1fb4y147qw/
package io.github.jihch.service;
import io.github.jihch.bean.ExpressInfo;
import io.github.jihch.exception.ClientException;
import io.github.jihch.mapper.ExpressMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import java.awt.datatransfer.Clipboard;
import java.time.Duration;
public class ExpressInfoService implements IExpressInfoService {
@Autowired
RedisTemplate redisTemplate;
@Autowired
ExpressMapper expressMapper;
/**
* 通过发货单查询物流信息
* @param id
* @return
*/
@Override
public ExpressInfo findByDeliveryOrderId(Long id) {
String key = "xushu-express:express-info:";
//从 Redis 查询物流信息
Object obj = redisTemplate.opsForValue().get(key + id);
if (obj != null) {
return (ExpressInfo) obj;
} else {
ExpressInfo expressInfo = expressMapper.selectByDeliveryOrderId(id);
if (expressInfo != null) {
redisTemplate.opsForValue().set(key+id, expressInfo, Duration.ofHours(2));
return expressInfo;
} else {
throw new ClientException("发货单:{} 的物流信息不存在", id);
}
}//end else
}
}
但这种一般实现,不足以应对高并发的场景,可能会出现缓存击穿、缓存穿透、雪崩的问题
缓存击穿
假设这样的场景:高并发情况下,像上面的这种一般实现,一个 key 一开始是不在缓存里的,或者它设置了失效时间在某一个时间点失效,
但它又是一个访问频率非常高的 key,那么当大量请求密集访问这个接口的时候,就会出现因为缓存中没有这个 key,然后都去查询数据库,就会导致数据库性能下降甚至崩溃。