如何保证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 更新缓存适合大型、分布式、高并发场景,因为它解耦、统一、可重试,维护成本更低。

相关推荐
gameboy03140 分钟前
从MySQL迁移到PostgreSQL的完整指南
数据库·mysql·postgresql
xdl25991 小时前
Spring Boot中集成MyBatis操作数据库详细教程
数据库·spring boot·mybatis
回到原点的码农1 小时前
Spring Data JDBC 详解
java·数据库·spring
zb200641201 小时前
Spring Boot 实战:轻松实现文件上传与下载功能
java·数据库·spring boot
CSharp精选营1 小时前
SQL Server安装避坑:这8个奇葩报错你遇到过几个?
数据库·sql server·安装指南·避坑
一勺菠萝丶1 小时前
Flowable + Spring 集成踩坑:流程结束监听器查询历史任务为空 & 获取不到审批意见
java·数据库·spring
RDCJM2 小时前
mysql表添加索引
数据库·mysql
czlczl200209253 小时前
Redis命令处理逻辑模型
数据库·redis·缓存
楼兰胡杨3 小时前
面试题|MySQL 的 3 层主键索引最多能支撑多少数据量
mysql·面试题
spring2997923 小时前
LangChain-08 Query SQL DB 通过GPT自动查询SQL
数据库·sql·langchain