Redis

关注公众号 jb51net

关闭
首页 > 数据库 > Redis > Redis和数据库双写一致性问题

Redis和数据库双写一致性问题的解决方案

作者:Java自学之旅

文章探讨了Redis与数据库双写一致性问题,提出四种解决方案:先更新数据库再删除缓存(推荐),延时双删避免并发不一致,监听数据库变更实现最终一致性,加分布式锁保障强一致,核心原则是优先保证数据库正确性,缓存操作可失败重试,强一致性需牺牲性能

下面我将详细解答Redis与数据库双写一致性问题,结合故事举例说明,最后用思维导图总结核心解决方案。

问题解答

核心问题:当同时更新Redis缓存和数据库时,由于网络延迟、操作顺序等问题导致数据不一致。

解决方案(含故事举例)

假设电商平台有商品库存系统:

// 商品服务类
public class ProductService {
    private DB db = new MySQL();  // 数据库
    private Cache cache = new Redis();  // 缓存
}

1. 先更新数据库,再删除缓存(推荐方案)

public void updateProduct(Product product) {
    db.update(product);          // 1. 更新数据库
    cache.delete(product.getId());// 2. 删除缓存
}

故事场景

管理员修改商品价格(100→80元):

用户查询时:

优势

风险

并发时短暂不一致(概率低):

2. 延时双删策略

public void updateWithDelay(Product product) {
    cache.delete(product.getId());    // 1. 先删缓存
    db.update(product);               // 2. 更新数据库
    Thread.sleep(500);                // 3. 等待500ms
    cache.delete(product.getId());    // 4. 再删缓存
}

故事场景

解决上述并发问题:

3. 监听数据库变更(最终一致性)

// 使用Canal监听MySQL binlog
canal.subscribe(event -> {
    if (event.isUpdate()) {
        cache.delete(event.getKey()); // 异步删除缓存
    }
});

故事场景

订单系统库存变更:

4. 加分布式锁(强一致)

public void safeUpdate(Product product) {
    Lock lock = redisson.getLock("PRODUCT_" + product.getId());
    lock.lock();
    try {
        db.update(product);
        cache.update(product); // 同时更新缓存
    } finally {
        lock.unlock();
    }
}

适用场景

金融账户余额等强一致性要求:

总结对比

方案一致性性能复杂度适用场景
先DB后删缓存最终★★★★大部分业务
延时双删最终★★★高并发场景
监听binlog最终★★★★异构系统同步
分布式锁强一致★★金融/账户系统

核心原则

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

您可能感兴趣的文章:
阅读全文