redis常用场景-java示例

假设 Redis 依赖:

XML 复制代码
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

Redis 配置:

XML 复制代码
spring:
  redis:
    host: localhost
    port: 6379

一、缓存(Cache)

场景:
查询商品信息,先查缓存,没有再查数据库

代码:

java 复制代码
@Service
public class ProductService {

    @Autowired
    private StringRedisTemplate redisTemplate;

    public String getProduct(Long id) {

        String key = "product:" + id;

        // 1 查询缓存
        String product = redisTemplate.opsForValue().get(key);

        if (product != null) {
            return product;
        }

        // 2 查询数据库(模拟)
        product = queryProductFromDB(id);

        // 3 写入缓存
        redisTemplate.opsForValue().set(key, product, 10, TimeUnit.MINUTES);

        return product;
    }

    private String queryProductFromDB(Long id) {
        return "商品信息:" + id;
    }
}

Redis 数据:

复制代码
product:1001 -> 商品信息

优点:

复制代码
减少数据库压力
提高查询速度

二、消息队列(简单队列)

Redis 可以用 List 实现简单 MQ。

生产者:

java 复制代码
@Service
public class MessageProducer {

    @Autowired
    private StringRedisTemplate redisTemplate;

    public void sendMessage(String msg) {

        redisTemplate.opsForList().leftPush("order_queue", msg);

        System.out.println("发送消息:" + msg);
    }
}

消费者:

java 复制代码
@Service
public class MessageConsumer {

    @Autowired
    private StringRedisTemplate redisTemplate;

    @PostConstruct
    public void consume() {

        new Thread(() -> {

            while (true) {

                String msg = redisTemplate.opsForList()
                        .rightPop("order_queue", 10, TimeUnit.SECONDS);

                if (msg != null) {
                    System.out.println("消费消息:" + msg);
                }
            }

        }).start();
    }
}

Redis 结构:

复制代码
List: order_queue

生产消费流程:

复制代码
Producer -> LPUSH
Consumer -> BRPOP

三、排行榜(Leaderboard)

Redis Sorted Set 非常适合排行榜。

场景:

复制代码
游戏积分排行榜

代码:

java 复制代码
@Service
public class RankService {

    @Autowired
    private StringRedisTemplate redisTemplate;

    // 添加用户分数
    public void addScore(String userId, double score) {

        redisTemplate.opsForZSet()
                .add("game_rank", userId, score);
    }

    // 获取排行榜前10
    public Set<ZSetOperations.TypedTuple<String>> top10() {

        return redisTemplate.opsForZSet()
                .reverseRangeWithScores("game_rank", 0, 9);
    }

    // 查询用户排名
    public Long getRank(String userId) {

        return redisTemplate.opsForZSet()
                .reverseRank("game_rank", userId);
    }
}

Redis 数据:

复制代码
ZSET game_rank
user1 1000
user2 900
user3 800

排行榜获取:

复制代码
ZRANGE game_rank 0 9 WITHSCORES

四、会话存储(Session)

常见于:

复制代码
用户登录状态
Token
Session

代码:

java 复制代码
@Service
public class SessionService {

    @Autowired
    private StringRedisTemplate redisTemplate;

    public String login(Long userId) {

        String token = UUID.randomUUID().toString();

        String key = "login:token:" + token;

        redisTemplate.opsForValue()
                .set(key, userId.toString(), 30, TimeUnit.MINUTES);

        return token;
    }

    public String getUser(String token) {

        String key = "login:token:" + token;

        return redisTemplate.opsForValue().get(key);
    }

    public void logout(String token) {

        redisTemplate.delete("login:token:" + token);
    }
}

Redis 数据:

复制代码
login:token:xxx -> userId

访问流程:

复制代码
登录
  ↓
生成 token
  ↓
存入 Redis
  ↓
后续请求带 token
  ↓
Redis 校验

五、真实互联网系统 Redis 使用比例

常见场景占比大概:

复制代码
缓存            60%
分布式锁        10%
排行榜          10%
消息队列         5%
Session         10%
限流             5%

六、缓存穿透(布隆过滤器)

问题:

复制代码
请求不存在的数据
缓存没有
数据库没有
每次都打到数据库

解决:

复制代码
BloomFilter

代码:

java 复制代码
@Service
public class ProductService {

    @Autowired
    private StringRedisTemplate redisTemplate;

    private BloomFilter<Long> bloomFilter = 
        BloomFilter.create(Funnels.longFunnel(), 1000000);

    @PostConstruct
    public void init() {

        // 假设初始化数据库已有ID
        for(long i = 1; i <= 100000; i++){
            bloomFilter.put(i);
        }
    }

    public String getProduct(Long id) {

        if (!bloomFilter.mightContain(id)) {
            return null;
        }

        String key = "product:" + id;

        String value = redisTemplate.opsForValue().get(key);

        if (value != null) {
            return value;
        }

        String product = queryDB(id);

        if (product == null) {
            redisTemplate.opsForValue().set(key,"null",5,TimeUnit.MINUTES);
            return null;
        }

        redisTemplate.opsForValue().set(key, product, 30, TimeUnit.MINUTES);

        return product;
    }

    private String queryDB(Long id) {
        return "商品" + id;
    }
}

七、缓存击穿(互斥锁)

问题:

复制代码
热点key突然过期
大量请求同时查数据库

解决:

复制代码
Redis互斥锁

代码:

java 复制代码
public String getProduct(Long id) {

    String key = "product:" + id;

    String value = redisTemplate.opsForValue().get(key);

    if(value != null){
        return value;
    }

    String lockKey = "lock:product:" + id;

    Boolean lock = redisTemplate.opsForValue()
            .setIfAbsent(lockKey,"1",10,TimeUnit.SECONDS);

    if(Boolean.TRUE.equals(lock)){

        try {

            value = redisTemplate.opsForValue().get(key);

            if(value != null){
                return value;
            }

            value = queryDB(id);

            redisTemplate.opsForValue()
                    .set(key,value,30,TimeUnit.MINUTES);

        }finally {

            redisTemplate.delete(lockKey);
        }

    }else{

        try {
            Thread.sleep(50);
        } catch (InterruptedException e) {
        }

        return getProduct(id);
    }

    return value;
}

八、缓存雪崩

问题:

复制代码
大量key同一时间过期
数据库瞬间被打爆

解决:

复制代码
过期时间 + 随机值

代码:

java 复制代码
public void setCache(String key,String value){

    int base = 30;

    int random = new Random().nextInt(10);

    redisTemplate.opsForValue().set(
            key,
            value,
            base + random,
            TimeUnit.MINUTES
    );
}

效果:

复制代码
原来:

10:00 同时过期

现在:

10:00
10:03
10:07
10:09

避免同时失效。


九、分布式锁(Redisson)

真实项目 99% 用 Redisson

代码:

java 复制代码
@Service
public class OrderService {

    @Autowired
    private RedissonClient redissonClient;

    public void createOrder(Long userId){

        RLock lock = redissonClient.getLock("order_lock:" + userId);

        try{

            lock.lock();

            System.out.println("创建订单");

        }finally {

            lock.unlock();
        }
    }
}

Redisson内部:

复制代码
SET NX PX
Lua解锁
WatchDog自动续期

十、接口限流(Lua + Redis)

场景:

复制代码
接口每秒最多10次请求

Lua脚本:

Lua 复制代码
local key = KEYS[1]
local limit = tonumber(ARGV[1])
local current = tonumber(redis.call('get', key) or "0")

if current + 1 > limit then
    return 0
else
    redis.call("INCR", key)
    redis.call("EXPIRE", key, 1)
    return 1
end

Java代码:

java 复制代码
public boolean limit(String ip){

    String script = "...lua脚本...";

    DefaultRedisScript<Long> redisScript =
            new DefaultRedisScript<>(script, Long.class);

    Long result = redisTemplate.execute(
            redisScript,
            Collections.singletonList("limit:" + ip),
            "10"
    );

    return result == 1;
}

请求流程:

复制代码
请求
 ↓
Redis计数
 ↓
超过10次
 ↓
拒绝

十一、延迟队列

Redis ZSet实现延迟任务

场景:

复制代码
订单30分钟未支付自动取消

生产者:

java 复制代码
public void addDelayTask(String orderId){

    long time = System.currentTimeMillis() + 30 * 60 * 1000;

    redisTemplate.opsForZSet()
            .add("order_delay", orderId, time);
}

消费者:

java 复制代码
@PostConstruct
public void start(){

    new Thread(() -> {

        while(true){

            Set<String> orders =
                    redisTemplate.opsForZSet()
                            .rangeByScore("order_delay",
                                    0,
                                    System.currentTimeMillis(),
                                    0,
                                    1);

            if(orders == null || orders.isEmpty()){
                continue;
            }

            String orderId = orders.iterator().next();

            redisTemplate.opsForZSet().remove("order_delay",orderId);

            cancelOrder(orderId);

        }

    }).start();
}

private void cancelOrder(String orderId){

    System.out.println("取消订单:" + orderId);
}

Redis结构:

复制代码
ZSET order_delay

order1 1710000000
order2 1710000500

总结(互联网Redis核心场景)

场景 Redis结构
缓存 String
布隆过滤 BloomFilter
排行榜 ZSet
消息队列 List
延迟队列 ZSet
分布式锁 String
限流 String + Lua
相关推荐
成为你的宁宁2 小时前
【Kubernetes Secret 安全配置指南:从创建配置到环境变量、数据卷使用及私有镜像仓库实践】
java·安全·kubernetes
xieliyu.2 小时前
Java手搓数据结构:从零模拟实现顺序表增删改查
java·开发语言·数据结构·学习·顺序表
没有羊的王K2 小时前
机器学习指标解析:AUC与KS值
开发语言·python
千江明月2 小时前
Ollama安装的详细步骤以及Python调用Qwen
开发语言·python·ollama·qwen模型
小凡子空白在线学习2 小时前
工作中设计模式内容
java·后端·spring
高林雨露2 小时前
Java开发转kotlin
java·kotlin
Wenzar_2 小时前
# 发散创新:SwiftUI 中状态管理的深度实践与重构艺术 在 SwiftUI 的世界里,**状态驱动 UI 是核心哲学**。但随
java·python·ui·重构·swiftui
of Watermelon League2 小时前
Redis 下载与安装 教程 windows版
数据库·windows·redis
不败公爵2 小时前
finsh_thread_entry这个线程是自动启动的
java·linux·服务器