商户查询的缓存——基于逻辑过期方式解决缓存击穿问题

 

//基于逻辑过期方式解决缓存基穿问题  理论上讲都是可以命中的
public Shop queryWithLogincalExpire(Long id){
    //1.从redis中查商铺缓存
    String jsonShop = stringRedisTemplate.opsForValue().get(CACHE_SHOP_KEY + id);
    //2.未命中
    if(StringUtils.isBlank(jsonShop)){
        //说明根本没有该商品
       return null;
    }
    //3.命中,需要将jsonShop进行反序列化
    RedisData redisData = JSONUtil.toBean(jsonShop, RedisData.class);
    JSONObject data = (JSONObject) redisData.getData();
    Shop shop = JSONUtil.toBean(data, Shop.class);
    //4.判断是否过期

    if(redisData.getExpireTime().isAfter(LocalDateTime.now())){
       //未过期 直接返回
        return shop;
    }
    String key=LOCK_SHOP_KEY+id;
    //5.过期
    boolean flag = tryLock(key);
    //6.判断是否获得锁
    if(flag){
        try {
            //7.是
            //7.1开启独立线程
            CACHE_REBUILD_EXECUTOR.submit(() -> {
                //重建缓存
                this.saveShop2Redis(id, 20L);
            });
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            unlock(key);
        }
    }
    //8.返回旧数据
    return shop;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,下面是解决缓存击穿问题逻辑过期代码: ``` public class RedisUtil { private static final Logger logger = LoggerFactory.getLogger(RedisUtil.class); private static final Long SUCCESS = 1L; private static final String SET_IF_NOT_EXIST = "NX"; private static final String SET_WITH_EXPIRE_TIME = "PX"; private static final String LOCK_PREFIX = "redis_lock_"; private static final String OK = "OK"; private static final String UNLOCK_LUA; static { StringBuilder sb = new StringBuilder(); sb.append("if redis.call(\"get\",KEYS[1]) == ARGV[1] "); sb.append("then "); sb.append(" return redis.call(\"del\",KEYS[1]) "); sb.append("else "); sb.append(" return 0 "); sb.append("end "); UNLOCK_LUA = sb.toString(); } private JedisPool jedisPool; public RedisUtil(JedisPool jedisPool) { this.jedisPool = jedisPool; } /** * 获取分布式锁 * * @param lockKey 锁 * @param requestId 请求标识 * @param expireTime 超期时间 * @return 是否获取成功 */ public boolean tryGetDistributedLock(String lockKey, String requestId, int expireTime) { Jedis jedis = jedisPool.getResource(); String result = jedis.set(lockKey, requestId, SET_IF_NOT_EXIST, SET_WITH_EXPIRE_TIME, expireTime); jedis.close(); return OK.equals(result); } /** * 释放分布式锁 * * @param lockKey 锁 * @param requestId 请求标识 * @return 是否释放成功 */ public boolean releaseDistributedLock(String lockKey, String requestId) { Jedis jedis = jedisPool.getResource(); Object result = jedis.eval(UNLOCK_LUA, Collections.singletonList(lockKey), Collections.singletonList(requestId)); jedis.close(); return SUCCESS.equals(result); } /** * 获取缓存 * * @param key 缓存key * @return 缓存值 */ public String get(String key) { Jedis jedis = jedisPool.getResource(); String value = jedis.get(key); jedis.close(); return value; } /** * 设置缓存 * * @param key 缓存key * @param value 缓存值 * @return 是否设置成功 */ public boolean set(String key, String value) { Jedis jedis = jedisPool.getResource(); String result = jedis.set(key, value); jedis.close(); return OK.equals(result); } /** * 设置缓存并带过期时间 * * @param key 缓存key * @param value 缓存值 * @param expireTime 过期时间,单位秒 * @return 是否设置成功 */ public boolean setWithExpireTime(String key, String value, int expireTime) { Jedis jedis = jedisPool.getResource(); String result = jedis.setex(key, expireTime, value); jedis.close(); return OK.equals(result); } /** * 缓存逻辑过期 * * @param key 缓存key * @param expireSeconds 过期时间,单位秒 * @param getDataFunc 获取数据的函数 * @return 缓存值 */ public String getOrSetWithExpireLogic(String key, int expireSeconds, Supplier<String> getDataFunc) { String value = get(key); if (value == null) { // 获取分布式锁 String requestId = UUID.randomUUID().toString(); boolean lockResult = tryGetDistributedLock(LOCK_PREFIX + key, requestId, expireSeconds * 1000); if (lockResult) { // 获取数据 value = getDataFunc.get(); if (value != null) { // 设置缓存并带过期时间 setWithExpireTime(key, value, expireSeconds); logger.info("set cache success, key={}, expireSeconds={}", key, expireSeconds); } // 释放分布式锁 releaseDistributedLock(LOCK_PREFIX + key, requestId); } else { // 获取锁失败,等待一段时间后重试 try { Thread.sleep(100); } catch (InterruptedException e) { logger.error("线程等待异常", e); } // 递归调用自身 return getOrSetWithExpireLogic(key, expireSeconds, getDataFunc); } } return value; } } ``` 这段代码实现了一个缓存逻辑过期的功能。当缓存失效时,先获取分布式锁,然后再次检查缓存是否存在,如果不存在,则执行获取数据的函数,然后设置缓存并带过期时间,最后释放分布式锁。如果获取分布式锁失败,则等待一段时间后重试。这样可以避免缓存击穿问题

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值