Redis缓存工具封装实现(redis作为缓存在项目中怎么使用命令)新鲜出炉

随心笔谈2年前发布 admin
166 0 0

文章摘要

这篇文章介绍了一个Java类`CacheClient`,用于实现Redis缓存功能。该类使用Spring框架的`@Component`和`@Slf4j`进行配置,主要功能包括: 1. **数据设置**:通过`set`和`setWithLogicExpire`方法向Redis中设置键值对,支持时间戳和单位参数。 2. **数据查询**: - `queryWithPassThrough`方法从Redis中获取数据,判断数据是否存在,并对过期数据进行重建。 - `queryWithLogicalExpire`方法更复杂的查询逻辑,不仅检查数据是否过期,还会尝试重新获取数据,并在必要时启动缓存重建。 3. **缓存重建**:定义了`CACHE_REBUILD_EXECUTOR`固定线程池,用于在数据过期时自动重建缓存。 4. **锁管理**:实现了获取和释放锁的逻辑,确保数据访问的并发安全性和一致性。 该类通过Redis缓存和Spring框架的配置,实现了高效的键值对存储和查询功能,适合分布式系统中的缓存管理和数据持久化。

@Component
@Slf4j
public class CacheClient {

? ? private final StringRedisTemplate stringRedisTemplate;

? ? public CacheClient(StringRedisTemplate stringRedisTemplate) {
? ? ? ? this.stringRedisTemplate=stringRedisTemplate;
? ? }

? ? public void set(String key, Object value, Long time, TimeUnit unit) {
? ? ? ? stringRedisTemplate.opsForValue().set(key, JSONUtil.toJsonStr(value), time, unit);
? ? }

? ? public void setWithLogicExpire(String key, Object value, Long time, TimeUnit unit) {
? ? ? ? RedisData redisData=new RedisData();
? ? ? ? redisData.setData(value);
? ? ? ? redisData.setExpireTime(LocalDateTime.now().plusSeconds(unit.toSeconds(time)));
? ? ? ? stringRedisTemplate.opsForValue().set(key, JSONUtil.toJsonStr(redisData));
? ? }

? ? public <R, ID> R queryWithPassThrough(String keyPrefix, ID id, Class<R> type,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? Long time, TimeUnit unit, Function<ID, R> dbFallback) {
? ? ? ? String key=keyPrefix + id;
? ? ? ? //1.从redis中查询商铺缓存
? ? ? ? String json=stringRedisTemplate.opsForValue().get(key);
? ? ? ? //2.判断是否存在
? ? ? ? if (StrUtil.isNotBlank(json)) {
? ? ? ? ? ? //2.1.存在
? ? ? ? ? ? return JSONUtil.toBean(json, type);
? ? ? ? }
? ? ? ? //2.2.不存在
? ? ? ? //判断是否为空值
? ? ? ? if (json !=null) {
? ? ? ? ? ? //不为null,则必为空
? ? ? ? ? ? return null;
? ? ? ? }
? ? ? ? //3.查询数据库
? ? ? ? R r=dbFallback.apply(id);
? ? ? ? if (r==null) {
? ? ? ? ? ? //3.1.不存在,缓存空值
? ? ? ? ? ? stringRedisTemplate.opsForValue().set(key, “”, CACHE_NULL_TTL, TimeUnit.MINUTES);
? ? ? ? } else {
? ? ? ? ? ? //3.2.存在,缓存数据
? ? ? ? ? ? this.set(key, r, time, unit);
? ? ? ? }
? ? ? ? return r;
? ? }

? ? public <R, ID> R queryWithLogicalExpire(String prefix, ID id, String lockPre, Class<R> type,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? Long time, TimeUnit unit, Function<ID, R> dbFallback) {
? ? ? ? //1.从redis查询商铺缓存
? ? ? ? String key=prefix + id;
? ? ? ? String json=stringRedisTemplate.opsForValue().get(key);
? ? ? ? //2.判断是否存在
? ? ? ? if (StrUtil.isBlank(json)) {
? ? ? ? ? ? //未命中,直接返回空
? ? ? ? ? ? return null;
? ? ? ? }
? ? ? ? //3.命中,判断是否过期
? ? ? ? RedisData redisData=JSONUtil.toBean(json, RedisData.class);
? ? ? ? R r=JSONUtil.toBean((JSONObject) redisData.getData(), type);
? ? ? ? if (redisData.getExpireTime().isAfter(LocalDateTime.now())) {
? ? ? ? ? ? //3.1未过期,直接返回店铺信息
? ? ? ? ? ? return r;
? ? ? ? }
? ? ? ? //3.2.已过期,缓存重建
? ? ? ? //3.3.获取锁
? ? ? ? String lockKey=lockPre + id;
? ? ? ? boolean flag=tryLock(lockKey);
? ? ? ? if (flag) {
? ? ? ? ? ? //3.4.获取成功
? ? ? ? ? ? //4再次检查redis缓存是否过期,做double check
? ? ? ? ? ? json=stringRedisTemplate.opsForValue().get(key);
? ? ? ? ? ? //4.1.判断是否存在
? ? ? ? ? ? if (StrUtil.isBlank(json)) {
? ? ? ? ? ? ? ? //未命中,直接返回空
? ? ? ? ? ? ? ? return null;
? ? ? ? ? ? }
? ? ? ? ? ? //4.2.命中,判断是否过期
? ? ? ? ? ? redisData=JSONUtil.toBean(json, RedisData.class);
? ? ? ? ? ? r=JSONUtil.toBean((JSONObject) redisData.getData(), type);
? ? ? ? ? ? if (redisData.getExpireTime().isAfter(LocalDateTime.now())) {
? ? ? ? ? ? ? ? //4.3.未过期,直接返回店铺信息
? ? ? ? ? ? ? ? return r;
? ? ? ? ? ? }
? ? ? ? ? ? //4.4过期,返回旧数据
? ? ? ? ? ? CACHE_REBUILD_EXECUTOR.submit(() -> {
? ? ? ? ? ? ? ? //5.重建缓存
? ? ? ? ? ? ? ? try {
? ? ? ? ? ? ? ? ? ? R r1=dbFallback.apply(id);
? ? ? ? ? ? ? ? ? ? this.setWithLogicExpire(key, r1, time, unit);
? ? ? ? ? ? ? ? } catch (Exception e) {
? ? ? ? ? ? ? ? ? ? throw new RuntimeException(e);
? ? ? ? ? ? ? ? } finally {
? ? ? ? ? ? ? ? ? ? //释放锁
? ? ? ? ? ? ? ? ? ? unLock(lockKey);
? ? ? ? ? ? ? ? }
? ? ? ? ? ? });
? ? ? ? }
? ? ? ? //7.获取失败,返回旧数据
? ? ? ? return r;
? ? }

? ? private static final ExecutorService CACHE_REBUILD_EXECUTOR=Executors.newFixedThreadPool(10);

? ? //获取锁
? ? private boolean tryLock(String key) {
? ? ? ? Boolean flag=stringRedisTemplate.opsForValue().setIfAbsent(key, “1”, LOCK_SHOP_TTL, TimeUnit.SECONDS);
? ? ? ? return BooleanUtil.isTrue(flag);
? ? }

? ? //释放锁
? ? private void unLock(String key) {
? ? ? ? stringRedisTemplate.delete(key);
? ? }
}

© 版权声明

相关文章