对于实时性要求不高的数据,在 Redis 作为缓存的情况下,保证 Redis 和数据库数据的一致性,可以选择缓存更新策略,常见的方案包括:
适用场景:数据读取多、实时性要求不高的场景(比如商品详情、用户信息等)。
// 读取数据
public String getDataFromCache(Long id) {
String key = "data:" + id;
String value = redisTemplate.opsForValue().get(key);
if (value != null) {
return value; // 直接返回缓存数据
}
// 缓存未命中,查询数据库
value = database.queryById(id);
// 写入 Redis,并设置过期时间
redisTemplate.opsForValue().set(key, value, Duration.ofMinutes(10));
return value;
}
// 更新数据
public void updateData(Long id, String newValue) {
// 先更新数据库
database.updateById(id, newValue);
// 删除 Redis 缓存
redisTemplate.delete("data:" + id);
// 延迟 500ms 再次删除,防止并发问题
new Timer().schedule(new TimerTask() {
@Override
public void run() {
redisTemplate.delete("data:" + id);
}
}, 500);
}
✅ 适用于读多写少的业务场景,能有效减少数据库压力。
✅ 避免缓存和数据库数据不一致的问题(先删缓存)。
✅ 结合延迟双删策略,在高并发情况下也能减少不一致。
适用场景:读写比例均衡,对一致性要求高的场景。
public void updateData(Long id, String newValue) {
// 先更新数据库
database.updateById(id, newValue);
// 同步更新 Redis
redisTemplate.opsForValue().set("data:" + id, newValue, Duration.ofMinutes(10));
}
✅ 读性能高,数据实时同步,减少不一致问题。
✅ 适用于读写并发均衡的业务(如用户状态、账户余额)。
❌ 写入数据时,Redis 也要同步更新,增加了写操作的延迟。
❌ 如果 Redis 更新失败,可能导致缓存和数据库数据不一致。
适用场景:写入频繁、对数据实时性要求不高的场景,如日志收集、订单队列等。
public void writeData(Long id, String newValue) {
// 先写入 Redis
redisTemplate.opsForValue().set("data:" + id, newValue);
// 记录变更到队列
messageQueue.send("update-db", id);
}
// 定时任务(或 MQ 消费者)批量更新数据库
@Scheduled(fixedRate = 5000)
public void batchUpdateDatabase() {
List ids = messageQueue.receive("update-db");
if (!ids.isEmpty()) {
database.batchUpdate(ids);
}
}
✅ 高吞吐写入,减少数据库压力(因为数据库只需批量写入)。
✅ 适用于日志、订单、点击数据等高并发写入的业务。
❌ 数据持久化到数据库有延迟,不适用于实时性要求高的业务。
❌ 断电或 Redis 故障可能导致数据丢失,需要配合持久化方案(AOF、RDB、MQ)。
方案 | 适用场景 | 一致性 | 读性能 | 写性能 | 复杂度 |
---|---|---|---|---|---|
Cache Aside(推荐) | 读多写少,数据实时性要求不高(如商品详情) | ⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐ |
Write Through | 读写比例均衡,数据一致性要求高(如用户状态) | ⭐⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐ | ⭐⭐ |
Write Behind | 写多读少,允许短时间数据延迟(如日志、订单) | ⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐ |
推荐方案
这样可以在性能和一致性之间找到平衡!