大好网站,西部数码网站管理助手 提权,深圳高端画册设计公司,中卫网站设计厂家Redis-缓存击穿-逻辑过期实现
缓存击穿#xff1a;也称热点key问题#xff0c;大量访问一个key#xff0c;而这个key恰巧到期了#xff0c;导致大量的请求访问数据库。增大数据库的负担。为了解决这个问题可以采用互斥锁或逻辑过期的方式解决。本章采用逻辑过期的方式解决…Redis-缓存击穿-逻辑过期实现
缓存击穿也称热点key问题大量访问一个key而这个key恰巧到期了导致大量的请求访问数据库。增大数据库的负担。为了解决这个问题可以采用互斥锁或逻辑过期的方式解决。本章采用逻辑过期的方式解决此问题。
流程图
第一点需要进行缓存预热把经常用的key预先缓存到redis中 /** 缓存数据KEY */private final String CACHE_SHOP_KEY CACHE_SHOP_KEY:;/** 缓存互斥锁KEY */private final String CACHE_SHOP_LOCK_KEY CACHE_SHOP_LOCK_KEY:;Autowiredprivate StringRedisTemplate stringRedisTemplate;private static final ExecutorService CACHE_REBUILD_EXECUTOR Executors.newFixedThreadPool(10);/*** redis缓存* 缓存击穿*/Overridepublic BooksVo selectById(Long bookId) {// 缓存击穿-互斥锁// return tryCacheMutex(bookId);// 缓存击穿-逻辑过期时间return tryCacheMutex2(bookId);}/*** redis缓存* 缓存击穿-逻辑过期版本* param bookId*/private BooksVo tryCacheMutex2(Long bookId) {// RedisKeyString cacheKey CACHE_SHOP_KEY bookId;// 1.从Redis查询商铺缓存// 获取缓存数据String contentBook stringRedisTemplate.opsForValue().get(cacheKey);// 2.判断缓存是否命中if (StringUtils.isBlank(contentBook)){// 3.1缓存未命中 直接返回结果return null;}// 3.2缓存命中-获取数据RedisData redisData JSONUtil.toBean(contentBook, RedisData.class);BooksVo booksVo JSONUtil.toBean((JSONObject) redisData.getData(), BooksVo.class);LocalDateTime expireSecond redisData.getExpireSecond();// 4.缓存未过期 直接返回数据if (expireSecond.isAfter(LocalDateTime.now())){return booksVo;}// 5.缓存过期-获取互斥锁if (tryLock(bookId)){// check doubleString s stringRedisTemplate.opsForValue().get(cacheKey);RedisData redisData1 JSONUtil.toBean(s, RedisData.class);if (BooleanUtil.isFalse(redisData1.getExpireSecond().isAfter(LocalDateTime.now()))){// 获取互斥锁成功,开启独立线程缓存重建CACHE_REBUILD_EXECUTOR.submit(() - {try {// 重建缓存saveCacheBook(bookId, 20L);} catch (Exception e) {throw new RuntimeException(e);} finally {// 释放互斥锁stringRedisTemplate.delete(CACHE_SHOP_LOCK_KEY bookId);}});}}// 返回已过期的数据return booksVo;}/*** 保存缓存信息*/public void saveCacheBook(Long bookId, Long expireSeconds){// 1.查询数据库数据BooksVo booksVo this.queryById(bookId);// 2.封装逻辑过期时间RedisData redisData new RedisData();redisData.setData(booksVo);// 获取当前的时间 指定秒数redisData.setExpireSecond(LocalDateTime.now().plusSeconds(expireSeconds));// 3.写入redisstringRedisTemplate.opsForValue().set(CACHE_SHOP_KEY bookId, JSONUtil.toJsonStr(redisData));}redisData实体类
Data
public class RedisData {/** 逻辑过期时间 */private LocalDateTime expireSecond;/** 拓展实体类 */private Object data;
}