导读:本期聚焦于小伙伴创作的《并发删除缓存与更新数据库:先删除缓存还是先更新数据库?》,敬请观看详情,探索知识的价值。以下视频、文章将为您系统阐述其核心内容与价值。如果您觉得《并发删除缓存与更新数据库:先删除缓存还是先更新数据库?》有用,将其分享出去将是对创作者最好的鼓励。

在分布式系统的缓存使用场景中,缓存和数据库的数据一致性是需要重点解决的问题,尤其是并发环境下的删除缓存与更新数据库操作,操作顺序的不同会直接导致不同的数据一致性结果,两种常见操作顺序各有其适用场景和潜在风险。

并发删除缓存与更新数据库:先删除缓存还是先更新数据库?

两种常见操作顺序分析

方案一:先删除缓存,再更新数据库

这种方案的操作逻辑是,当业务需要更新数据时,首先删除缓存中的旧数据,然后再执行数据库的更新操作。

在单线程场景下,这个方案看起来没有问题,但在并发场景下会出现数据不一致的问题。假设有两个并发请求,一个是更新请求A,一个是查询请求B:

  • 请求A先执行删除缓存操作,此时缓存中已无对应数据
  • 请求B查询数据,发现缓存不存在,于是去数据库查询旧数据
  • 请求B将查询到的旧数据写入缓存
  • 请求A才执行完数据库的更新操作,此时数据库已经是新数据,但缓存中是旧数据,出现数据不一致

对应的代码逻辑示例如下:

// 先删除缓存再更新数据库示例
public void updateDataFirstDeleteCache(String key, Object newData) {
    // 1. 删除缓存
    redisTemplate.delete(key);
    // 2. 更新数据库,这里模拟数据库更新操作
    userMapper.updateById(newData);
}

方案二:先更新数据库,再删除缓存

这种方案的操作逻辑是,先执行数据库的更新操作,完成后再删除缓存中的旧数据。

同样在并发场景下分析,假设更新请求A和查询请求B并发执行:

  • 请求B查询缓存,缓存中存在数据,直接返回旧数据(此时还没到更新数据库的步骤,属于正常情况)
  • 请求A执行更新数据库操作,将数据库数据更新为新值
  • 请求A删除缓存
  • 后续新的查询请求会去数据库查询新数据,再写入缓存,数据恢复一致

这种方案出现数据不一致的概率极低,只有在更新数据库成功但删除缓存失败的极端情况下才会出现问题,对应的代码示例如下:

// 先更新数据库再删除缓存示例
public void updateDataFirstUpdateDB(String key, Object newData) {
    // 1. 更新数据库
    userMapper.updateById(newData);
    // 2. 删除缓存
    redisTemplate.delete(key);
}

并发场景下的风险优化

先删除缓存方案的优化

针对先删除缓存再更新数据库的并发不一致问题,可以使用延迟双删策略优化。也就是在更新数据库完成后,延迟一段时间再次删除缓存,避免查询请求写入旧数据到缓存。

代码示例如下:

// 延迟双删优化示例
public void updateDataWithDelayDoubleDelete(String key, Object newData) {
    // 1. 第一次删除缓存
    redisTemplate.delete(key);
    // 2. 更新数据库
    userMapper.updateById(newData);
    // 3. 延迟500ms再次删除缓存,延迟时间根据业务查询耗时调整
    try {
        Thread.sleep(500);
    } catch (InterruptedException e) {
        Thread.currentThread().interrupt();
    }
    redisTemplate.delete(key);
}

先更新数据库方案的优化

针对先更新数据库再删除缓存的删除失败问题,可以引入重试机制。当删除缓存失败时,将删除操作放入消息队列,异步重试删除,直到删除成功。

代码示例如下:

// 删除缓存重试机制示例
public void updateDataWithRetryDelete(String key, Object newData) {
    // 1. 更新数据库
    userMapper.updateById(newData);
    // 2. 尝试删除缓存
    boolean deleteSuccess = redisTemplate.delete(key);
    if (!deleteSuccess) {
        // 删除失败,将key放入消息队列重试
        retryDeleteCacheQueue.offer(key);
    }
}

// 异步重试线程示例
class RetryDeleteThread extends Thread {
    @Override
    public void run() {
        while (true) {
            String key = retryDeleteCacheQueue.poll();
            if (key != null) {
                try {
                    redisTemplate.delete(key);
                } catch (Exception e) {
                    // 重试失败再次放入队列
                    retryDeleteCacheQueue.offer(key);
                }
            }
        }
    }
}

方案选择建议

如果业务对数据一致性要求不是特别高,且更新操作频率较低,优先选择先更新数据库再删除缓存的方案,实现简单,出现不一致的概率极低。

如果业务更新操作非常频繁,且对数据一致性要求较高,可以考虑使用先删除缓存+延迟双删的方案,或者结合分布式锁保证更新和查询操作的互斥性,避免并发冲突。

无论选择哪种方案,都建议做好缓存删除失败的监控和告警,及时发现数据不一致问题,避免影响业务正常运行。

缓存数据库并发操作缓存更新策略修改时间:2026-06-15 12:12:34

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。