赞
踩
SpringCloud章节复习已经过去,新的章节Redis开始了,这个章节中将会回顾Redis实战项目 大众点评
主要依照以下几个原则
代码会同步在我的gitee中去,觉得不错的同学记得一键三连求关注,感谢:
Redis优化-链接: RedisThreeStrategiesProject
上一节已经讲了下互斥锁
互斥锁本身是ok的,但是将当前资源锁住,后面的用户 只能查询等待
有没有更好的解决方式那?
这里可以设计逻辑过期时间
我们定义一个逻辑过期时间
@Data
public class RedisData {
private LocalDateTime expireTime;
private Object object;
}
public void saveShop2Redis(Long id, Long expireSeconds){
Shop shop = getById(id);
RedisData data = new RedisData();
data.setObject(shop);
data.setExpireTime(LocalDateTime.now().plusSeconds(expireSeconds));
stringRedisTemplate.opsForValue().set(RedisConstants.CACHE_SHOP_KEY + id, JSONUtil.toJsonStr(data));
}
@SpringBootTest
class HmDianPingApplicationTests {
@Resource
private ShopServiceImpl shopService;
@Test
void testSaveShop(){
for (int i = 1; i < 15; i++) {
Long value = Long.valueOf(i);
shopService.saveShop2Redis(value, 10L);
}
}
}
//逻辑过期 个人写 并不能实现异步 还是阻塞
public Result queryById2(Long id) {
String key = RedisConstants.CACHE_SHOP_KEY + id;
String shopStr = stringRedisTemplate.opsForValue().get(key);
if(StrUtil.isBlank(shopStr)){
return Result.fail("NULL");
}
RedisData data = JSONUtil.toBean(shopStr, RedisData.class);
Shop shop = JSONUtil.toBean((JSONObject) data.getObject(), Shop.class);
if(data.getExpireTime().isAfter(LocalDateTime.now())){
return Result.ok(shop);
}
//过期了,就通过独立线程 -> 互斥锁处理缓存击穿
String lockKey = RedisConstants.LOCK_SHOP_KEY + id;
try {
if (!tryLock(lockKey)) {
Thread.sleep(50);
return queryById(id);
}
shop = getById(id);
log.debug("lockKey: " + lockKey + " shopByDB " + shop);
if (shop == null) {
return Result.fail("店铺类型不存在!");
}
data.setExpireTime(LocalDateTime.now().plusSeconds(3600));
stringRedisTemplate.opsForValue().set(key, JSONUtil.toJsonStr(data), RedisConstants.CACHE_NULL_TTL, TimeUnit.HOURS);
} catch (InterruptedException e) {
throw new RuntimeException(e);
/*e.printStackTrace();*/
}finally {
//删除暂时的key, 释放互斥锁
stringRedisTemplate.delete(lockKey);
}
return Result.ok(shop);
}
private static final ExecutorService CACHE_REBUILD_EXECUTOR = Executors.newFixedThreadPool(10);
@Override //逻辑过期时间 通过线程池进行处理
public Result queryById(Long id) {
//这里就是所有的热点数据保存到了Redis,直接去拿,热点数据没有TTL,只有过期时间这一字段
String key = RedisConstants.CACHE_SHOP_KEY + id;
String shopStr = stringRedisTemplate.opsForValue().get(key);
if(StrUtil.isBlank(shopStr)){
return Result.fail("店铺资格过期");
}
RedisData data = JSONUtil.toBean(shopStr, RedisData.class);
Shop shop = JSONUtil.toBean((JSONObject) data.getObject(), Shop.class);
if(data.getExpireTime().isAfter(LocalDateTime.now())){
return Result.ok(shop);
}
//过期了,就通过独立线程 -> 互斥锁处理缓存击穿
String lockKey = RedisConstants.LOCK_SHOP_KEY + id;
if (!tryLock(lockKey)) {
log.debug("lockKey: " + lockKey + " shopByDB " + shop);
CACHE_REBUILD_EXECUTOR.submit(()->{
try {
this.saveShop2Redis(id, 10L);
} catch (Exception e) {
throw new RuntimeException(e);
/*e.printStackTrace();*/
}finally {
//删除暂时的key, 释放互斥锁
stringRedisTemplate.delete(lockKey);
}
});
}
if(shop==null){
return Result.fail("店铺不存在");
}
return Result.ok(shop);
}
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。