Redis

关注公众号 jb51net

关闭
首页 > 数据库 > Redis > Redis 业务中用法

Redis 在业务中的典型用法汇总

作者:晴天sir

文章主要介绍了Redis在业务中的六种常见应用场景,包括缓存access_token、存储业务状态、计数器、分布式锁、消息队列、标签和排行榜等,通过SpringBoot+RedisTemplate的方式进行实现,感兴趣的朋友跟随小编一起看看吧

最近在做小程序后端时,用 Redis 解决了几个典型问题:缓存 access_token、记录用户订阅状态、分布式锁防止并发。借此机会,我总结了 Redis 在业务中最常用的几种模式,希望对大家有帮助。相关代码,可以参考  wx小程序实战

一、为什么选择 Redis?

首先 Redis 是一款基于内存的键值存储系统,速度快、数据结构丰富、支持持久化。在需要高性能缓存分布式锁计数器消息队列等场景下,Redis 几乎是首选。

我将以 Spring Boot + RedisTemplate 为例,展示几种常见用法。

二、用法一:缓存(String 类型 + 过期时间)

场景

微信小程序的 access_token 有效期为 2 小时(7200 秒),且每日获取次数有限(2000 次)。必须缓存起来,避免频繁调用。

实现

// 获取 token
String token = redisTemplate.opsForValue().get("WECHAT_ACCESS_TOKEN");
if (token == null) {
    token = fetchFromWechat();
    redisTemplate.opsForValue().set("WECHAT_ACCESS_TOKEN", token, 7000, TimeUnit.SECONDS);
}

关键点

三、用法二:存储业务状态(String 类型 + 过期时间)

场景

用户订阅消息后,需要在后端记录订阅关系,30 天后自动失效(与微信授权有效期对齐)。

实现

String key = "SUBSCRIBE:" + templateId + ":" + openId;
redisTemplate.opsForValue().set(key, "1", 30, TimeUnit.DAYS);
// 检查是否订阅
Boolean exists = redisTemplate.hasKey(key);

扩展

可以用 Hash 存储一个用户订阅的多个模板:hset user:openId templateId 1

但简单场景下 String 更直观

四、用法三:计数器(自增/自减)

场景

限制用户每天发送意见的次数(防刷)。例如每个村民每天最多提交 3 条意见。

实现

String key = "OPINION:LIMIT:" + openId + ":" + LocalDate.now();
Long count = redisTemplate.opsForValue().increment(key);
if (count == 1) {
 // 设置过期时间为当天结束
    redisTemplate.expire(key, 1, TimeUnit.DAYS);
}
if (count > 3) {
    return Result.error("今日提交次数已达上限");
}

其他应用

五、用法四:分布式锁(String + setIfAbsent + Lua)

场景

多实例部署时,缓存失效瞬间多个线程同时请求微信 access_token,导致 token 被覆盖或超限。需要分布式锁保证只有一个线程去刷新。

实现

String lockKey = "WECHAT:ACCESS_TOKEN_LOCK";
String lockValue = UUID.randomUUID().toString();
Boolean locked = redisTemplate.opsForValue()
        .setIfAbsent(lockKey, lockValue, 5, TimeUnit.SECONDS);
if (locked) {
    try {
        // 双重检查
        String token = redisTemplate.opsForValue().get("WECHAT_ACCESS_TOKEN");
        if (token == null) {
            token = fetchFromWechat();
            redisTemplate.opsForValue().set("WECHAT_ACCESS_TOKEN", token, 7000, TimeUnit.SECONDS);
        }
        return token;
    } finally {
        // 释放锁:Lua 脚本保证原子性,只释放自己加的锁
        String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
        redisTemplate.execute(new DefaultRedisScript<>(script, Long.class), 
                Collections.singletonList(lockKey), lockValue);
    }
} else {
    // 睡 100ms 后重试
    Thread.sleep(100);
    return getAccessToken();
}

注意

六、用法五:消息队列(List / PubSub)

场景

异步处理耗时任务,例如发送订阅消息后需要记录日志,但不影响主流程响应。

用 List 实现简单队列

// 生产者:入队
redisTemplate.opsForList().rightPush("MSG:QUEUE", message);
// 消费者:阻塞弹出(配合 while 循环或定时任务)
String message = redisTemplate.opsForList().leftPop("MSG:QUEUE", 10, TimeUnit.SECONDS);

用 Pub/Sub 实现广播

// 发布
redisTemplate.convertAndSend("CHANNEL:OPINION", "新意见");
// 订阅(需实现 MessageListener)
@Bean
public MessageListenerAdapter listenerAdapter(RedisReceiver receiver) {
    return new MessageListenerAdapter(receiver, "onMessage");
}

对比

方式特点适用场景
List点对点,支持阻塞等待简单任务队列
Pub/Sub广播,消息即发即失(不持久化)实时通知、聊天
Stream(5.0+)持久化、消费组可靠消息队列

七、用法六:Set / SortedSet 实现标签和排行榜

Set 应用:用户标签系统

// 给用户打标签
redisTemplate.opsForSet().add("TAG:GRID_MEMEBER", openId1, openId2);
// 判断是否网格员
Boolean isGrid = redisTemplate.opsForSet().isMember("TAG:GRID_MEMEBER", openId);

SortedSet 应用:排行榜

// 增加积分
redisTemplate.opsForZSet().incrementScore("RANK:OPINION", openId, 1);
// 获取前三名
Set<String> top3 = redisTemplate.opsForZSet().reverseRange("RANK:OPINION", 0, 2);

八、总结

数据结构典型用法你的项目中的应用
String缓存、计数器、分布式锁access_token、订阅状态、限流
Hash存储对象字段(可扩展)用户配置
List消息队列异步任务
Set标签、去重用户角色标识
SortedSet排行榜、延迟队列积分排行
Pub/Sub实时广播通知推送

ok,结束。

到此这篇关于Redis 在业务中的几种典型用法的文章就介绍到这了,更多相关Redis 业务中用法内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文