redis的manager层应用

本文涉及的产品
云数据库 Redis 版,社区版 2GB
推荐场景:
搭建游戏排行榜
云数据库 RDS MySQL Serverless,0.5-2RCU 50GB
云数据库 RDS MySQL Serverless,价值2615元额度,1个月
简介: redis的manager层应用

一身报国有万死,双鬓向人无再青。 —— 陆游

封装了一个操作redis的管理层,简单处理了缓存穿透、击穿、雪崩问题

Manager

package com.ruben.manager;
import com.alibaba.fastjson.TypeReference;
import java.util.function.Supplier;
/**
 * redis管理层
 *
 * @author <achao1441470436@gmail.com>
 * @since 2021/6/11 0011 21:55
 */
public interface RedisManager {
    /**
     * 从缓存中获取否则从mysql中查询
     *
     * @param key           缓存中的key
     * @param mysqlSupplier 查询mysql操作
     * @param typeReference 返回的类型
     * @param <T>           数据类型
     * @return 数据
     */
    <T> T getFromRedisOrPutIntoMysql(String key, Supplier<T> mysqlSupplier, TypeReference<T> typeReference);
}

实现类

package com.ruben.manager;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.baomidou.mybatisplus.core.exceptions.MybatisPlusException;
import com.ruben.utils.Opt;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.security.SecureRandom;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
import java.util.function.Supplier;
/**
 * redis管理层实现类
 *
 * @author <achao1441470436@gmail.com>
 * @since 2021/6/11 0011 21:55
 */
@Service
public class RedisManagerImpl implements RedisManager {
    public static final SecureRandom SECURE_RANDOM = new SecureRandom();
    /**
     * 过期时间
     */
    public static final int EXPIRE_SECONDS = 5 * 60 * 1000;
    @Resource
    private StringRedisTemplate stringRedisTemplate;
    /**
     * 从缓存中获取否则从mysql中查询
     *
     * @param key           缓存中的key
     * @param mysqlSupplier 查询mysql操作
     * @param typeReference 返回的类型
     * @param <T>           数据类型
     * @return 数据
     */
    @Override
    @Transactional(readOnly = true, propagation = Propagation.NOT_SUPPORTED, isolation = Isolation.READ_UNCOMMITTED)
    public <T> T getFromRedisOrPutIntoMysql(String key, Supplier<T> mysqlSupplier, TypeReference<T> typeReference) {
        // 判断传入key是否为空
        Opt.ofNullable(key).filter(StringUtils::isNotEmpty)
                .orElseThrow(() -> new MybatisPlusException("key不能为空"));
        // 如果redis中存在,直接返回
        String value = stringRedisTemplate.opsForValue().get(key);
        if (Objects.nonNull(value)) {
            return JSON.parseObject(value, typeReference);
        }
        // 查数据库并放入缓存这个操作加锁【缓存击穿】
        synchronized (this) {
            // 否则从数据库中取出
            return Opt.ofNullable(mysqlSupplier).map(Supplier::get)
                    // 如果有值则放入缓存,随机时间【缓存雪崩】
                    .peek(v -> stringRedisTemplate.opsForValue()
                            .set(key, JSON.toJSONString(v), SECURE_RANDOM.nextInt(EXPIRE_SECONDS), TimeUnit.SECONDS))
                    // 没值则放入空对象"{}"【缓存穿透】并返回null
                    .orElseGet(() -> {
                        stringRedisTemplate.opsForValue()
                                .set(key, "{}", SECURE_RANDOM.nextInt(EXPIRE_SECONDS), TimeUnit.SECONDS);
                        return null;
                    });
        }
    }
}

使用方式

@Resource
private RedisManager redisManager;
@Test
public void managerTest() {
    List<String> userIds = redisManager.getFromRedisOrPutIntoMysql("userIds", () -> {
        // 从数据库中查询...
        return Arrays.asList("1", "2", "3");
    }, new TypeReference<List<String>>() {
    });
    System.out.println(userIds);
}

目前自己开发中用着感觉还不错的,大伙可以拿去自定义

相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore &nbsp; &nbsp; ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库&nbsp;ECS 实例和一台目标数据库&nbsp;RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&amp;RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
相关文章
|
27天前
|
存储 NoSQL Redis
保障数据安全,提升性能:探秘Redis AOF持久化机制在在线购物网站的应用
保障数据安全,提升性能:探秘Redis AOF持久化机制在在线购物网站的应用
|
27天前
|
存储 消息中间件 NoSQL
Redis数据类型详解:选择合适的数据结构优化你的应用
Redis数据类型详解:选择合适的数据结构优化你的应用
|
3月前
|
存储 NoSQL 安全
Redis相关命令详解及其原理:Redis基本操作、数据结构以及应用
Redis相关命令详解及其原理:Redis基本操作、数据结构以及应用
96 0
|
2月前
|
消息中间件 NoSQL Java
Redis Streams在Spring Boot中的应用:构建可靠的消息队列解决方案【redis实战 二】
Redis Streams在Spring Boot中的应用:构建可靠的消息队列解决方案【redis实战 二】
246 1
|
1月前
|
缓存 NoSQL Java
分布式项目中锁的应用(本地锁-_redis【setnx】-_redisson-_springcache)-fen-bu-shi-xiang-mu-zhong-suo-de-ying-yong--ben-de-suo--redissetnx-springcache-redisson(一)
分布式项目中锁的应用(本地锁-_redis【setnx】-_redisson-_springcache)-fen-bu-shi-xiang-mu-zhong-suo-de-ying-yong--ben-de-suo--redissetnx-springcache-redisson
59 0
|
1月前
|
缓存 NoSQL Redis
分布式项目中锁的应用(本地锁-_redis【setnx】-_redisson-_springcache)-fen-bu-shi-xiang-mu-zhong-suo-de-ying-yong--ben-de-suo--redissetnx-springcache-redisson(二)
分布式项目中锁的应用(本地锁-_redis【setnx】-_redisson-_springcache)-fen-bu-shi-xiang-mu-zhong-suo-de-ying-yong--ben-de-suo--redissetnx-springcache-redisson
39 0
|
1月前
|
Cloud Native NoSQL 数据管理
Serverless 应用引擎常见问题之首次启动获取不到redis连接如何解决
Serverless 应用引擎(Serverless Application Engine, SAE)是一种完全托管的应用平台,它允许开发者无需管理服务器即可构建和部署应用。以下是Serverless 应用引擎使用过程中的一些常见问题及其答案的汇总:
31 3
Serverless 应用引擎常见问题之首次启动获取不到redis连接如何解决
|
1月前
|
存储 缓存 NoSQL
探索Redis的多样应用场景:加速和优化现代应用
探索Redis的多样应用场景:加速和优化现代应用
34 2
|
1月前
|
存储 消息中间件 NoSQL
Redis 常见数据类型(对象类型)和应用案列
接下来,让我们走进 Redis 的对象世界,Redis 5.0版本就已经支持了下面的 9 种类型,分别是 :字符串对象、列表对象、哈希对象、集合对象、有序集合对象、Bitmaps 对象、HyperLogLog 对象、Geospatial 对象、Stream对象。
Redis 常见数据类型(对象类型)和应用案列
|
1月前
|
缓存 NoSQL 安全
【Redis】2、Redis应用之【根据 Session 和 Redis 进行登录校验和发送短信验证码】
【Redis】2、Redis应用之【根据 Session 和 Redis 进行登录校验和发送短信验证码】
51 0