redis 的一些使用场景
一、Redis String一场景短信验证码用于注册、登录、找回密码、换绑手机号场景我们用 Redis String 类型存储验证码。Key 设计分两类验证码存储sms:code:13800138000value 存 6 位数字验证码过期 5 分钟发送限流防刷sms:limit:13800138000统计手机号发送次数控制一分钟最多 1 条、一小时最多 5 条。完整业务流程用户请求发送验证码接口第一步先查限流 key判断是否频繁发送没超限就生成 6 位验证码用原子set key value EX 300存入 Redis同时给限流 key 自增计数设置一小时过期再调用短信服务商下发短信。用户登录提交手机号 验证码时从 Redis 取出对应手机号的验证码对比匹配成功直接删除 Redis 里的验证码避免重复使用匹配失败返回提示。优化点用原子命令防止宕机残留数据限流拦截恶意频繁刷短信验证码验证后立即删除保证一次性有效Redis 自动过期兜底不用手动清理过期验证码。二完整业务实现代码 详细逻辑1. 核心 Redis 命令说明存验证码原子操作同时设置 5 分钟过期redisSET sms:code:13800138000 654321 EX 300限流计数一分钟最多 1 次redisINCR sms:limit:13800138000 EXPIRE sms:limit:13800138000 3600校验通过后删除验证码redisDEL sms:code:138001380002. Java 完整工具 Controller 代码工具类javaimport org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Component; import javax.annotation.Resource; import java.util.Random; import java.util.concurrent.TimeUnit; Component public class SmsCodeRedisUtil { Resource private RedisTemplateString, String redisTemplate; // 验证码过期时间 5分钟 private static final int CODE_EXPIRE 300; // 限流总周期 1小时 private static final int LIMIT_EXPIRE 3600; // 一小时最多发送5条 private static final int MAX_SEND_COUNT 5; /** * 1. 判断手机号是否频繁发送限流校验 */ public boolean checkSendLimit(String phone) { String limitKey sms:limit: phone; String countStr redisTemplate.opsForValue().get(limitKey); int count countStr null ? 0 : Integer.parseInt(countStr); // 超过5次直接拦截 return count MAX_SEND_COUNT; } /** * 2. 生成并保存验证码到Redis */ public String generateAndSaveCode(String phone) { // 生成6位数字验证码 String code String.format(%06d, new Random().nextInt(1000000)); String codeKey sms:code: phone; // 原子存入验证码过期时间 redisTemplate.opsForValue().set(codeKey, code, CODE_EXPIRE, TimeUnit.SECONDS); // 发送次数自增 String limitKey sms:limit: phone; Long count redisTemplate.opsForValue().increment(limitKey); // 第一次计数时设置过期时间 if (count 1) { redisTemplate.expire(limitKey, LIMIT_EXPIRE, TimeUnit.SECONDS); } return code; } /** * 3. 校验验证码成功后删除验证码一次性使用 */ public boolean verifyCode(String phone, String inputCode) { String codeKey sms:code: phone; String realCode redisTemplate.opsForValue().get(codeKey); if (realCode null || !realCode.equals(inputCode)) { return false; } // 验证通过立刻删除防止重复使用 redisTemplate.delete(codeKey); return true; } }接口控制器javaimport org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import javax.annotation.Resource; RestController public class SmsController { Resource private SmsCodeRedisUtil smsCodeRedisUtil; // 发送验证码接口 GetMapping(/sms/send) public String sendCode(RequestParam String phone) { // 1. 限流校验 if (!smsCodeRedisUtil.checkSendLimit(phone)) { return 操作频繁1小时内最多获取5条验证码; } // 2. 生成验证码存入Redis String code smsCodeRedisUtil.generateAndSaveCode(phone); // 模拟调用第三方短信服务商发送短信 System.out.println(给手机号 phone 发送验证码 code); return 发送成功; } // 登录校验验证码接口 PostMapping(/login) public String login(RequestParam String phone, RequestParam String code) { boolean pass smsCodeRedisUtil.verifyCode(phone, code); if (pass) { return 登录成功; } return 验证码错误或已过期; } }三生产环境核心优化 面试加分点验证码一次性失效校验成功立刻DEL删除 Redis key避免同一个验证码多次登录就算不手动删5 分钟自动过期兜底。防刷限流双重控制用 Redis 计数器限制单手机号一小时最多 5 条防止恶意刷短信消耗第三方短信费用。原子命令避免数据残留存储验证码使用SET key value EX 300单条原子命令不会出现 “存了验证码但没设置过期时间” 的宕机漏洞。内存友好无堆积所有验证码、限流 key 都设置过期时间依靠 Redis 惰性 定期删除自动清理不会长期占用内存。分布式场景兼容单机 Redis 直接用这套方案集群环境使用 Redisson 保证原子操作多服务共享同一套验证码缓存。接口安全补充前端增加图形验证码防止接口被爬虫无限调用发送短信接口双重拦截恶意请求。二、String hash系统所有业务字典统一使用 Redis Hash 存储举商品类型举例Redis 的 key 固定为dict:product_typeHash 结构里 field 是数字编码value 是前端展示的中文比如编码 1 对应食品、0 对应实体商品。项目启动完成后会一次性把数据库里全部字典数据加载进 Redis后台运营新增、修改、删除字典项时会实时操作 Redis 同步更新对应 Hash同时给所有字典 key 设置 7 天过期时间兜底就算 Redis 缓存丢失过期后会自动重新加载数据库字典保证数据不会长期不一致。业务接口返回给前端时要求同时返回数字编码和对应的中文名称比如productType:1、productTypeDic:食品这里实现方案通用自动化方案核心解决不用手动赋值、自动新增xxxDic字段自定义注解DictConvertVO 中存数字编码的字段加上注解注解指定对应 Redis 字典类型比如DictConvert(dictType product_type)自定义 Jackson 全局序列化器所有接口返回 JSON 时都会走这个序列化逻辑序列化过程中会遍历 VO 的所有字段判断字段是否带有字典注解如果带注解取出当前字段的数字编码根据注解里的字典标识去 Redis 对应的 Hash 中查询中文文本输出 JSON 时先输出原有字段productType:1再额外自动拼接一个productTypeDic字段把查到的中文写入 JSON 返回给前端整个过程业务 Controller 完全不用写任何字典转换代码统一由框架处理。