如何保证redis和mysql数据一致性方案对比

一. 先更新数据库再更新缓存

  1. 业务代码中先 DB 后 Cache(不推荐)

updateDB();

updateCache();

原因:

  1. DB成功,Cache失败 缓存不一致 无法进行回滚

为啥使用@Transactional不能保证数据一致性?

@Transactional

public void update() {

updateDB(); // 数据库

updateCache(); // Redis / 本地缓存

}

上面代码的执行顺序:

1.updateDB() → 执行 SQL(未提交)

2.updateCache() → Redis 已更新

3.方法结束

4.事务提交(或回滚)

@Transactional满足条件?

@Transactional 的本质基于数据库的事务。

它只能保证:

1.多条数据库 SQL

2.在同一个数据源

3.同一个线程

4.同一个事务上下文

  1. 业务代码中先 DB ,再删除 Cache(推荐)但是会出现短暂不一致

@Transactional

public void update() {

updateDB();

}

public void afterUpdate() {

deleteCache();

}

流程:

更新 DB(事务)

提交成功

删除缓存

下次读 → 回源 DB → 重建缓存

二. 先更新缓存再更新数据库

结论:

先更新缓存再更新数据库的做法,永远无法保证数据严格的一致性。

原因:事务A更新缓存成功,更新数据库失败,就会导致redis和mysql的

数据不一致。

绝大多数场景不使用先更新缓存再更新数据库。

特殊场景:缓存为主,DB为辅。

思路:缓存是主存储,数据库只是持久化备份

适用场景:

游戏排行榜 / 计分系统

高频访问、对性能要求极高的热点数据

热点缓存需要立即生效,DB 延迟可接受

高吞吐、读多写少的场景

DB 写操作是瓶颈,先更新缓存可以减少 DB 压力

三. 双删策略

并发问题:并发读写导致的缓存脏数据

假设有 三个事务 A、B、C,涉及 DB + Redis 缓存?

事务A:

deleteCache() // 删除缓存

updateDB() // 更新数据库

DB还没有更新完成

还没执行第二次删除缓存

事务 B(读操作):

cache miss // 缓存已被删除

read DB // 读到旧值(事务 A 还没提交/更新完成)

write cache // 回写旧值到缓存

事务C:

读取缓存中旧的数据

四 . canal监听Binlog日志

双删策略对比canal监听Binlog日志的劣势?

双删策略缺点?

  1. 时间窗口不太好控制

如果 sleep 太短 → 不一致仍可能

如果 sleep 太长 → 延迟大,业务性能受影响

  1. 业务耦合

每个更新操作都要手动加双删逻辑

多服务、多表、多缓存的情况下,维护成本高

  1. 无法扩展到多个下游系统

比如缓存 + Elasticsearch + MQ

双删只能针对单个缓存,无法保证其他下游系统同步

canal 监听 Binlog 的优势?

DB update → MySQL binlog → Canal → 消费端处理 → 更新缓存 / 下游系统

  1. 完全解耦业务

业务代码只管 DB,不用关心缓存

不会增加每个更新的复杂度

  1. 可扩展性

一个Canal消费端可以同时同步缓存,搜索引擎,消息队列等。

多个下游系统共享同一条 Binlog 数据,保证最终一致性

统一容错处理

Canal 自带消费重试

消费失败可以回溯 binlog

远比双删"sleep+delete"可控

五、为什么大规模系统不用双删而用 Canal

维度 双删 Canal

业务 耦合 强,每个更新都要写双删 弱,业务只管 DB

多下游系统 每个系统都要自己写双删 一条 Binlog 可以同步多个系统

可靠性 不可控,sleep 仍可能不一致 可控,Binlog 消费可重试

扩展性 差 好,适合微服务和大流量系统

可维护性 差 好, 统 一逻辑

双删适合小型、单服务、低流量场景;

Canal + Binlog 更新缓存适合大型、分布式、高并发场景,因为它解耦、统一、可重试,维护成本更低。

相关推荐
rfidunion2 小时前
springboot+VUE+部署(9。安装MySql)
spring boot·后端·mysql
枷锁—sha2 小时前
【Vulhub】Discuz! 7.2 faq.php SQL 注入深度复现手册 (转义逃逸篇)
数据库·sql·php
超级种码2 小时前
Redis:Redis 常见问题及解决思路
数据库·redis·缓存
计算机学姐2 小时前
基于SpringBoot的社区互助系统
java·spring boot·后端·mysql·spring·信息可视化·推荐算法
xcLeigh2 小时前
Oracle 迁移 KingbaseES 避坑指南:工具选型、参数配置与性能调优
数据库·oracle·工具·性能·金仓·kingbasees
JY.yuyu2 小时前
SQL Server数据库
数据库
June bug2 小时前
【配环境】安装配置Oracle JDK
java·数据库·oracle
独自破碎E2 小时前
如何在MySQL中监控和优化慢SQL?
数据库·sql·mysql
数据库生产实战2 小时前
基础知识 | Oracle Index Split(索引分裂:你的数据库越来越慢可能与此有关!建议排查!
数据库·oracle