火爆了!Redis 18 大经典应用场景,一文掌握 Spring Boot 实战代码
大家都知道,Redis是基于内存读写、单线程原子操作和丰富的数据结构,使其既能作为缓存层降低数据库压力,也能承担分布式锁、计数器、排行榜、消息队列、限流等需要高性能和原子性的业务场景,是互联网高并发系统中使用频率极高的内存数据库。Redis的使用场景到底有哪些了?公众原文
热点数据缓存 (String/Hash)
业务案例:商品详情、用户信息。
核心原理:Cache-Aside 模式(先查缓存,没有则查数据库并写入缓存,设置 TTL)。
// RedisConfig.java(通用配置)
@Configuration
public class RedisConfig {
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
RedisTemplate<String, Object> template = new RedisTemplate<>();
template.setConnectionFactory(factory);
template.setKeySerializer(new StringRedisSerializer());
template.setValueSerializer(new GenericJackson2JsonRedisSerializer());
template.setHashKeySerializer(new StringRedisSerializer());
template.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());
return template;
}
}
// Service
@Service
public class CacheService {
@Autowired
private RedisTemplate<String, Object> redisTemplate;
@Autowired
private ProductMapper productMapper; // 数据库 Mapper
public Product getProduct(Long id) {
String key = "product:" + id;
Product product = (Product) redisTemplate.opsForValue().get(key);
if (product == null) {
product = productMapper.selectById(id); // 从DB查
if (product != null) {
redisTemplate.opsForValue().set(key, product, 30, TimeUnit.MINUTES); // Cache-Aside
}
}
return product;
}
// Hash(用户信息)
public void updateUserInfo(Long userId, String field, Object value) {
String key = "user:" + userId;
redisTemplate.opsForHash().put(key, field, value);
redisTemplate.expire(key, 1, TimeUnit.HOURS);
}
}
分布式会话 (String/Hash)
业务案例:单点登录 SSO、多实例 Session 共享。
核心原理:引入spring-session-data-redis 依赖后,Spring 会自动将 HttpSession 拦截并托管至 Redis。
引入依赖
<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session-data-redis</artifactId>
</dependency>
添加配置
application.yml
spring:
session:
store-type: redis
redis:
namespace: spring:session
redis:
host: localhost
port: 6379
无需额外代码,使用@EnableRedisHttpSession 即可实现多实例 Session 共享。
分布式锁 (String NX)
业务案例:秒杀防超卖、定时任务防重复执行。
核心原理:SETNX 加锁 + Lua 脚本原子解锁。生产环境推荐直接使用 Redisson。
@Service
public class LockService {
@Autowired
private RedisTemplate<String, Object> redisTemplate;
public boolean tryLock(String lockKey, String requestId, long expireMs) {
Boolean success = redisTemplate.opsForValue()
.setIfAbsent(lockKey, requestId, expireMs, TimeUnit.MILLISECONDS);
return Boolean.TRUE.equals(success);
}
// Lua 脚本释放锁(原子操作)
public boolean releaseLock(String lockKey, String requestId) {
String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
return Boolean.TRUE.equals(redisTemplate.execute(
new DefaultRedisScript<>(script, Boolean.class),
Collections.singletonList(lockKey), requestId));
}
}
计数器 (String)
业务案例:文章阅读量、点赞数、API 调用次数。
核心原理:INCR / INCRBY 原子自增。
public void incrementReadCount(Long articleId) {
String key = "article:read:" + articleId;
redisTemplate.opsForValue().increment(key); // INCR
redisTemplate.expire(key, 7, TimeUnit.DAYS);
}
public Long getReadCount(Long articleId) {
String key = "article:read:" + articleId;
return redisTemplate.opsForValue().increment(key, 0); // 读取
}
排行榜 (Sorted Set)
业务案例:游戏积分榜、电商热销榜。
核心原理:ZADD 写入分数,ZREVRANGE 降序查询。
@Service
public class LeaderboardService {
@Autowired
private StringRedisTemplate redisTemplate;
// 上传分数 / 增加分数
public void addScore(String userId, double score) {
redisTemplate.opsForZSet().incrementScore("game:leaderboard", userId, score);
}
// 获取前10名 (分数从高到低)
public Set<ZSetOperations.TypedTuple<String>> getTop10() {
return redisTemplate.opsForZSet().reverseRangeWithScores("game:leaderboard", 0, 9);
}
}
限流 (ZSet/String)
业务案例:API 频率限制(如:1分钟内最多请求100次)。
核心原理:滑动窗口限流(使用 ZSet 的 score 存时间戳,ZREMRANGEBYSCORE 移除窗口外的数据)。
@Component
public class RateLimiter {
@Autowired
private StringRedisTemplate redisTemplate;
public boolean isAllowed(String userId, String action, int maxCount, int windowSizeSeconds) {
String key = "limit:" + userId + ":" + action;
long now = System.currentTimeMillis();
long windowStart = now - (windowSizeSeconds * 1000);
// 1. 移除窗口外的数据
redisTemplate.opsForZSet().removeRangeByScore(key, 0, windowStart);
// 2. 获取当前窗口内的请求数
Long count = redisTemplate.opsForZSet().zCard(key);
if (count != null && count >= maxCount) {
return false; // 被限流
}
// 3. 记录本次请求
redisTemplate.opsForZSet().add(key, String.valueOf(now), now);
return true;
}
}
消息队列 (List/Stream)
业务案例:异步任务、日志收集。
核心原理:LPUSH + BRPOP 阻塞消费(List 简易模式),或使用具有持久化和 Ack 机制的 Stream。
@Service
public class QueueProducer {
@Autowired
private StringRedisTemplate redisTemplate;
public void sendTask(String taskJson) {
redisTemplate.opsForList().leftPush("task:queue", taskJson);
}
}
// 消费者线程 (简易消费示例)
@Component
class QueueConsumer implements CommandLineRunner {
@Autowired
private StringRedisTemplate redisTemplate;
@Override
public void run(String... args) {
new Thread(() -> {
while (true) {
// BRPOP 阻塞读取,超时时间 10 秒
String task = redisTemplate.opsForList().rightPop("task:queue", 10, TimeUnit.SECONDS);
if (task != null) {
System.out.println("处理异步任务: " + task);
}
}
}).start();
}
}
发布订阅 (Pub/Sub)
业务案例:实时弹幕推送、聊天室广播。
核心原理:PUBLISH / SUBSCRIBE 消息广播。
@Configuration
public class RedisPubSubConfig {
// 注册消息监听器容器
@Bean
RedisMessageListenerContainer container(RedisConnectionFactory connectionFactory,
MessageListenerAdapter listenerAdapter) {
RedisMessageListenerContainer container = new RedisMessageListenerContainer();
container.setConnectionFactory(connectionFactory);
container.addMessageListener(listenerAdapter, new PatternTopic("chat:room"));
return container;
}
@Bean
MessageListenerAdapter listenerAdapter(Receiver receiver) {
return new MessageListenerAdapter(receiver, "receiveMessage");
}
}
@Component
class Receiver {
public void receiveMessage(String message) {
System.out.println("收到弹幕/广播: " + message);
}
}
最新列表或时间线 (List)
业务案例:最新评论、朋友圈动态。
核心原理:LPUSH + LTRIM 裁剪,保持列表固定长度(如只保留最新100条)。
@Service
public class TimelineService {
@Autowired
private StringRedisTemplate redisTemplate;
public void addComment(Long articleId, String commentJson) {
String key = "article:comments:" + articleId;
// 1. 推入新评论
redisTemplate.opsForList().leftPush(key, commentJson);
// 2. 裁剪列表,只保留前 100 条
redisTemplate.opsForList().trim(key, 0, 99);
}
}
购物车 (Hash)
业务案例:电商购物车商品及数量增删改查。
核心原理:以用户ID为 Key,商品ID为 Field,数量为 Value。
@Service
public class CartService {
@Autowired
private StringRedisTemplate redisTemplate;
// 添加商品到购物车
public void addCart(Long userId, Long productId, int quantity) {
String key = "cart:" + userId;
redisTemplate.opsForHash().increment(key, String.valueOf(productId), quantity);
}
// 获取购物车所有商品及数量
public Map<Object, Object> getCart(Long userId) {
String key = "cart:" + userId;
return redisTemplate.opsForHash().entries(key);
}
}
签到或打卡 (Bitmap)
业务案例:用户每日签到、连续签到统计。
核心原理:按位(Bit)存储,用偏移量(Offset)表示天数,1为签到,0为未签到。
@Service
public class SignService {
@Autowired
private StringRedisTemplate redisTemplate;
// 签到:按年份和月份划分 key,offset 传当天日期减 1 (如 5号 对应 offset=4)
public void doSign(Long userId, int dayOfMonth) {
String key = "sign:" + userId + ":202607";
redisTemplate.opsForValue().setBit(key, dayOfMonth - 1, true);
}
// 统计本月签到次数
public Long getSignCount(Long userId) {
String key = "sign:" + userId + ":202607";
return redisTemplate.execute((RedisCallback<Long>) connection ->
connection.bitCount(key.getBytes()));
}
}
地理位置 LBS (Geo)
业务案例:附近的人、附近的店铺。
核心原理:GEOADD 写入经纬度,GEORADIUS / GEOSEARCH 范围检索。
@Service
public class ShopGeoService {
@Autowired
private StringRedisTemplate redisTemplate;
// 添加店铺位置
public void addShopLocation(String shopId, double lng, double lat) {
redisTemplate.opsForGeo().add("shops:location", new Point(lng, lat), shopId);
}
// 查询方圆 5 公里内的店铺
public GeoResults<RedisGeoCommands.GeoLocation<String>> getNearShops(double lng, double lat) {
Circle circle = new Circle(new Point(lng, lat), new Metric() {
public double getMultiplier() { return 0.001; } // 米转公里计算
public String getUnit() { return "km"; }
});
return redisTemplate.opsForGeo().search("shops:location", circle);
}
}
布隆过滤器 (Bloom Filter)
业务案例:缓存穿透防护。
核心原理:由于底层需要 BF.ADD 等扩展模块命令,默认 RedisTemplate 不直接支持,通常通过 Redisson 或执行 Lettuce原生/Lua 驱动。
// 使用 Redisson 实现最为标准和方便
@Service
public class BloomFilterService {
@Autowired
private RedissonClient redissonClient;
public void initBloom() {
RBloomFilter<String> bloomFilter = redissonClient.getBloomFilter("user:exists:filter");
// 初始化布隆过滤器:预期插入100万数据,误差率 3%
bloomFilter.tryInit(1000000L, 0.03);
bloomFilter.add("user123");
}
public boolean checkIfContains(String userId) {
RBloomFilter<String> bloomFilter = redissonClient.getBloomFilter("user:exists:filter");
return bloomFilter.contains(userId); // 高效判断是否存在,若返回 false 则绝对不存在
}
}
全局唯一 ID (String)
业务案例:分布式订单号生成。
核心原理:时间戳 + INCRBY 批量取号段,减少网络 IO。
@Component
public class OrderIdGenerator {
@Autowired
private StringRedisTemplate redisTemplate;
public long generateOrderId() {
String dateStr = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd"));
String key = "order:id:" + dateStr;
// 每次自增 1,结合日期组合成唯一 ID
Long increment = redisTemplate.opsForValue().increment(key);
return Long.parseLong(dateStr + String.format("%06d", increment));
}
}
社交关系 (Set)
业务案例:共同好友、关注与粉丝。
核心原理:SADD 建立集合,SINTER 求交集(共同好友),SDIFF 求差集(可能认识的人)。
@Service
public class SocialService {
@Autowired
private StringRedisTemplate redisTemplate;
// 关注某人
public void follow(Long userId, Long followUserId) {
redisTemplate.opsForSet().add("following:" + userId, String.valueOf(followUserId));
redisTemplate.opsForSet().add("followers:" + followUserId, String.valueOf(userId));
}
// 求共同关注 (交集)
public Set<String> getCommonFollowing(Long userA, Long userB) {
return redisTemplate.opsForSet().intersect("following:" + userA, "following:" + userB);
}
}
延迟任务 (Sorted Set)
业务案例:订单超时取消。
核心原理:将任务执行的绝对时间戳作为 Score 存入 ZSet,定时任务拉取已过期的 Score 进行消费。
@Service
public class DelayTaskService {
@Autowired
private StringRedisTemplate redisTemplate;
// 提交延迟任务
public void addDelayTask(String orderId, long delaySeconds) {
long executeTime = System.currentTimeMillis() + (delaySeconds * 1000);
redisTemplate.opsForZSet().add("order:delay:queue", orderId, executeTime);
}
// 定时轮询拉取过期任务 (一般用 Scheduled 触发)
@Scheduled(fixedRate = 1000)
public void consumeDelayTask() {
long now = System.currentTimeMillis();
// 获取所有分数小于等于当前时间戳的任务
Set<String> orderIds = redisTemplate.opsForZSet().rangeByScore("order:delay:queue", 0, now);
if (orderIds != null && !orderIds.isEmpty()) {
for (String orderId : orderIds) {
// 用 remove 保证分布式集群下只有一个节点抢到该任务
Long removed = redisTemplate.opsForZSet().remove("order:delay:queue", orderId);
if (removed != null && removed > 0) {
System.out.println("执行取消订单逻辑: " + orderId);
}
}
}
}
}
用户画像或UV 统计 (HyperLogLog)
业务案例:网页 UV 基数去重统计。
核心原理:PFADD 注入用户,PFCOUNT 模糊去重计数。标准误差 0.81%,极省内存。
@Service
public class UvService {
@Autowired
private StringRedisTemplate redisTemplate;
// 记录访问用户
public void recordVisit(String pageName, String userId) {
String key = "uv:" + pageName;
redisTemplate.opsForHyperLogLog().add(key, userId);
}
// 获取 UV 统计值
public Long getUvCount(String pageName) {
String key = "uv:" + pageName;
return redisTemplate.opsForHyperLogLog().size(key);
}
}
向量检索 (Vector - Redis Stack)
业务案例:AI 语义搜索、RAG 知识库召回。
核心原理:通过 Redis Stack 提供的 FT.SEARCH 命令执行 KNN 相似度检索。
// Spring Data Redis 官方需要借助 Jedis/Lettuce 原生或 RedisModulesCommands。
// 以下为基于 Jedis/Lettuce 原始客户端连接执行自定义指令的通用伪代码架构:
@Service
public class VectorSearchService {
@Autowired
private StringRedisTemplate redisTemplate;
public List<String> searchSimilarDocs(float[] queryVector, int topK) {
// 将 float[] 转换为 byte[] 字节流
byte[] vectorBytes = convertToBytes(queryVector);
// 构建 Redis 向量检索的原始命令 (FT.SEARCH index "(*)=>[KNN 5 @vector $vec] -> {$yield_distance_as: dist}" PARAMS 2 vec vectorBytes DIALECT 2)
String indexName = "doc_index";
String query = "(*)=>[KNN " + topK + " @doc_vector $vec]";
// 执行 Redis 原始命令进行 K 邻近 (KNN) 匹配并返回文档 ID
List<Object> results = redisTemplate.execute((RedisCallback<List<Object>>) connection -> {
// 通过底层原生客户端(如 RedisModules / FT.SEARCH 命令)进行复杂查询
// 返回召回的 TopK 条相似文本/实体 ID
return null;
});
return new ArrayList<>();
}
private byte[] convertToBytes(float[] input) {
ByteBuffer buffer = ByteBuffer.allocate(input.length * 4).order(ByteOrder.LITTLE_ENDIAN);
for (float v : input) buffer.putFloat(v);
return buffer.array();
}
}
Redis 数据存于内存,单位成本远高于磁盘,不适合存储大规模冷数据;海量数据场景需控制 key 数量与 value 体积,避免大 key 阻塞主线程。
更多推荐




所有评论(0)