航母指挥官2免安装绿色中文版
1.21G · 2025-09-11
大家好,我是大华!
在很多Java项目里,Redis就是个@Cacheable
,缓存个用户、商品,然后就没了。
但!Redis的本事远不止这点。
我在大厂搬砖的那段时间,用 Spring Boot+Redis 解决过一堆要命的问题。今天我就来分享10个真实又常用的Redis使用场景
场景 公司搞促销,优惠券的接口被黄牛用脚本疯狂刷,每秒几千的请求,服务器差点炸了。正常用户根本抢不到,页面卡成PPT。
问题 系统扛不住,资源被耗尽,用户体验非常差。
解决方案 用Redis记录每个用户的请求次数,每分钟最多10次,超过直接拒绝。
Java代码
public boolean isAllowed(String userId) {
String key = "rate_limit:" + userId;
// incr:自增1,如果key不存在,自动创建并设为1
Long count = redisTemplate.opsForValue().increment(key);
// 如果是第一次请求,设置60秒后自动过期
if (count == 1) {
redisTemplate.expire(key, 60, TimeUnit.SECONDS);
}
// 返回:是否允许(10次以内)
return count <= 10;
}
黄牛刷不动,系统稳了,用户能正常抢券。
场景 有时候用户手一抖,点了两下支付按钮,结果生成了两条订单!用户投诉、财务对不上账。
问题 多个服务实例同时处理同一个订单,数据冲突。
解决方案 用Redis加个锁,确保同一时间只有一个请求能处理这个订单。
lock:order_123
。Java代码
public boolean tryLock(String orderId) {
String key = "lock:order:" + orderId;
// setIfAbsent:只有key不存在时才设置,相当于“抢锁”
Boolean success = redisTemplate.opsForValue()
.setIfAbsent(key, "1", 10, TimeUnit.SECONDS);
return Boolean.TRUE.equals(success);
}
注意
场景 用户下单不付款,占着库存不放,别人想买也买不了。
传统做法 后台定时任务每分钟扫一遍数据库,查哪些订单超时了,再关闭。又慢又耗数据库资源。
Redis做法 用**ZSET(有序集合)**存订单,按超时时间戳排序。
Java代码
// 下单时:把订单加入延时队列
public void addDelayOrder(String orderId) {
long expireTime = System.currentTimeMillis() + 30 * 60 * 1000; // 30分钟后
redisTemplate.opsForZSet().add("order_delay", orderId, expireTime);
}
// 后台任务:每秒检查一次
@Scheduled(fixedRate = 1000)
public void checkExpiredOrders() {
long now = System.currentTimeMillis();
// 查出所有已超时的订单
Set<String> expiredOrders = redisTemplate.opsForZSet()
.rangeByScore("order_delay", 0, now);
if (expiredOrders != null) {
for (String orderId : expiredOrders) {
closeOrder(orderId); // 关闭订单逻辑
redisTemplate.opsForZSet().remove("order_delay", orderId); // 从队列移除
}
}
}
比扫库快多了,资源占用少,延迟基本在1秒内。
场景 搞活动,要实时显示今日下单最多的10个用户。
问题 用MySQL实时聚合统计,每次查询都慢,页面卡顿。
Redis做法
用ZSET,每个用户是成员,下单次数是分数。
Java代码
// 用户下单后,排行榜+1
public void addOrderToRank(String userId) {
redisTemplate.opsForZSet().incrementScore("today_rank", userId, 1);
}
// 获取TOP10
public Set<ZSetOperations.TypedTuple<String>> getTop10() {
return redisTemplate.opsForZSet()
.reverseRangeWithScores("today_rank", 0, 9);
}
排行榜秒刷新,运营小姐姐天天夸我。
场景
用户注册后要发邮件、发短信、打标签、推数据到数仓……如果全在注册流程里同步做,页面会卡顿!
问题
核心流程被非核心任务拖慢,用户体验差。
Redis做法
用List当简易消息队列。
Java代码
// 注册成功后,发消息
public void onUserRegistered(String userId) {
redisTemplate.opsForList().leftPush("user_event_queue", "register:" + userId);
}
// 后台Worker:异步处理
@Scheduled(fixedRate = 100)
public void processEvents() {
// rightPop:从List右边取一条消息,最多等1秒
String event = redisTemplate.opsForList()
.rightPop("user_event_queue", 1, TimeUnit.SECONDS);
if (event != null) {
handleEvent(event); // 异步处理发短信、打标签等
}
}
注册秒完成,用户体验起飞。消息还能持久化,不怕丢。
PS:第5个真的太香了,简单、快、稳,小公司完全够用。
场景
分布式系统,多个服务都要生成订单号,怕重复。
MySQL自增? 不行,跨库不好搞。
Redis做法
用INCR
命令,每次调用自动+1,返回唯一数字。
Java代码
public String generateOrderId() {
// 每次调用,自动+1
Long id = redisTemplate.opsForValue().increment("order_id_seq");
// 生成类似:ORDER_20240512123456_1001
return "ORDER_" + System.currentTimeMillis() + "_" + id;
}
优点:简单粗暴,全局唯一,性能好。
场景
做IM或社交功能,要显示“张三在线”。
传统做法
数据库存状态,频繁更新,IO爆炸。
Redis做法
用户上线,Redis里存个key,30秒过期。客户端每20秒发个心跳,刷新这个key。
原理
Redis自动过期机制,不用手动删。key存在就是在线,没了就是离线。
Java代码
// 用户上线或心跳
public void updateOnlineStatus(String userId) {
redisTemplate.opsForValue()
.set("online:" + userId, "1", 30, TimeUnit.SECONDS);
}
// 判断是否在线
public boolean isOnline(String userId) {
return Boolean.TRUE.equals(redisTemplate.hasKey("online:" + userId));
}
几百万人在线,Redis内存才占几G,查状态毫秒级。
场景
用户狂点“点赞”,数据库写入多条,统计全乱了。
Redis做法
用SET
记录用户对内容的操作。
like:user123:article456
这个key是否存在。Java代码
public boolean like(String userId, String articleId) {
String key = "like:" + userId + ":" + articleId;
Boolean exists = redisTemplate.hasKey(key);
if (Boolean.TRUE.equals(exists)) {
return false; // 已点赞
}
// 设置1小时过期
redisTemplate.opsForValue().set(key, "1", 1, TimeUnit.HOURS);
return true;
}
点赞去重,数据干净,再也不用半夜修数据了。
场景
用户登录后,把token和用户信息存哪?
存数据库? 慢!
存Cookie? 不安全!
Redis做法
登录成功后,把用户信息存到Redis,key是token,设置2小时过期。
Java代码
// 登录成功
public String login(User user) {
String token = UUID.randomUUID().toString();
String userJson = JSON.toJSONString(user);
redisTemplate.opsForValue()
.set("session:" + token, userJson, 2, TimeUnit.HOURS);
return token;
}
// 拦截器验证
public User getUserFromToken(String token) {
String userJson = redisTemplate.opsForValue().get("session:" + token);
return userJson != null ? JSON.parseObject(userJson, User.class) : null;
}
优点:快、安全、可集中管理(比如主动踢下线)。
场景
做秒杀,库存100件,怕超卖。
难点
MySQL扣库存并发高,容易出错。
Redis做法
提前把库存load到Redis。
DECR
命令原子性地减库存。Java代码
public boolean seckill(String goodsId, String userId) {
String key = "seckill:stock:" + goodsId;
// 原子性减1,返回减后的值
Long left = redisTemplate.opsForValue().decrement(key);
if (left >= 0) {
// 库存够,创建订单
createOrder(goodsId, userId);
return true;
}
return false;
}
注意:记得异步同步到数据库,防止Redis挂了丢数据。
当然Redis也不是万能的,适合数据量不大但访问频繁的场景。如果数据量特别大,还是得上专业解决方案。 工具不在多,用对才是王道。
《写给小公司前端的 UI 规范:别让页面丑得自己都看不下去》
《只会写 Mapper 就敢说会 MyBatis?面试官:原理都没懂》
《别学23种了!Java项目中最常用的6个设计模式,附案例》
《Vue3+TS设计模式:5个真实场景让你代码更优雅》
《Elasticsearch 太重?来看看这个轻量级的替代品 Manticore Search》
杭州萧山推出线下消费补贴:18-40 岁青年购 3C 数码产品最高可补 1000 元
努比亚张雷:手机市场从不是“非此即彼”的零和博弈,行业活力正来自这种差异化