Redis 在业务中的几种典型用法

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

一、为什么选择 Redis?

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

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

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

场景

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

实现

java 复制代码
// 获取 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 天后自动失效(与微信授权有效期对齐)。

实现

java 复制代码
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 条意见。

实现

java 复制代码
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 被覆盖或超限。需要分布式锁保证只有一个线程去刷新

实现

java 复制代码
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();
}

注意

  • 锁必须有过期时间,防止死锁

  • 释放锁时必须验证 value,防止误删他人的锁

  • 使用 Lua 脚本保证 get + del 的原子性

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

场景

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

用 List 实现简单队列

java 复制代码
// 生产者:入队
redisTemplate.opsForList().rightPush("MSG:QUEUE", message);

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

用 Pub/Sub 实现广播

java 复制代码
// 发布
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 应用:用户标签系统

java 复制代码
// 给用户打标签
redisTemplate.opsForSet().add("TAG:GRID_MEMEBER", openId1, openId2);

// 判断是否网格员
Boolean isGrid = redisTemplate.opsForSet().isMember("TAG:GRID_MEMEBER", openId);

SortedSet 应用:排行榜

java 复制代码
// 增加积分
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,结束。

相关推荐
WJX_KOI2 小时前
MemOS —— 为大语言模型 (LLMs) 和智能体打造的记忆操作系统。
java·人工智能·语言模型
jnrjian2 小时前
B树index 的维护 Oracle
数据库·oracle
_日拱一卒2 小时前
LeetCode:矩阵置零
java·数据结构·线性代数·算法·leetcode·职场和发展·矩阵
weixin_408099672 小时前
【实战教程】懒人精灵如何实现 OCR 文字识别?接口调用完整指南(附可运行示例)
java·前端·人工智能·后端·ocr·api·懒人精灵
正在走向自律2 小时前
企业级数据库存储运维实战:表空间自动创建与存储架构深度优化
运维·数据库·架构·表空间
jnrjian2 小时前
Oracle 并发 锁
数据库
爱码小白2 小时前
MySQL 常用数据类型的系统总结
数据库·python·算法
被摘下的星星2 小时前
MySQL drop和delete的区别
数据库·mysql
花千树-0102 小时前
Java Agent 集成 MCP 工具协议:让 AI 真正驱动企业系统
java·ai·langchain·ai agent·mcp·harness·j-langchain