一、业务场景做音乐网站项目每一次用户点击歌曲播放就需要该歌曲播放数加一。 假设并发量上来如果每一次播放请求直接 update 修改 MySQL。大量访问会频繁触发数据库写操作数据库压力会很高。于是想到使用 Redis 做中间缓存。播放先写到 Redis隔一段时间批量同步回 MySQL减少直接操作数据库的次数。二、实现思路1.用户点击播放后端接收请求2. 使用 Redis INCR原子命令对对应歌曲 id 的播放计数自增 1INCR 是原子操作不用担心并发冲突3. 开启 SpringBoot 定时任务每隔一段时间读取 Redis 里面所有歌曲播放增量4. 将增量批量更新 MySQL同步完成之后清空 Redis 里面已经落库的增量数据。注意隐患如果服务器突然宕机。Redis 还没来得及同步的数据会有丢失风险。 解决思路可以开启 Redis 持久化 RDB/AOF 降低丢数概率或者缩短定时任务间隔时间。三、核心关键代码片段1.播放量自增接口使用 RedisTemplate//歌曲id播放一次计数1 // redisKey格式play:count:{songId} String key play:count: songId; redisTemplate.opsForValue().increment(key);2.定时任务Scheduled每 10 分钟执行一次同步逻辑Component EnableScheduling public class PlayCountSyncTask { Resource private RedisTemplateString,Object redisTemplate; Resource private SongMapper songMapper; Scheduled(fixedDelay 10 * 60 * 1000) public void syncPlayCountToMysql(){ //1.查询redis中所有play:count开头的key //2.循环取出歌曲id和增量 //3.批量update mysql播放数量 //4.同步成功删除redis里面这一批key } }定时任务不要写太短间隔频繁同步就失去 Redis 缓冲意义太长宕机丢数风险变大。四、Redis‑MySQL 缓存不一致问题我们这套方案Redis 暂存增量定时任务批量同步。这是异步更新天然就容易出现缓存和数据库不一致。4.1当前项目会出现不一致的两种场景1.还没到定时同步时间MySQL 直接修改歌曲播放量后台手动改数据库数值。Redis 里面还保留旧增量同步之后就会叠加造成播放数量出错。2.定时任务执行一半程序宕机定时任务遍历一批 key一部分同步成功入库还没来得及删除 Redis 里对应的 key服务宕机。服务重启后定时任务再次执行会把这部分增量再次同步一遍造成播放量重复累加数据变多。注意普通用户点击播放只会往 Redis 做 increment不会直接写 MySQL。普通播放不会产生不一致人为修改 MySQL 才是不一致主要来源。4.2几种解决思路方案 1业务约束业务上约定所有播放量修改只能走 Redis。后台不允许直接手动修改 MySQL 播放量字段。优点实现零代码改动。适合课程演示。缺点现实生产环境很难强制所有人不碰数据库。方案 2更新 MySQL 同时主动清理对应 Redis Key如果后台需要修改歌曲播放量管理员编辑修改 MySQL 播放数字立刻删除该歌曲对应的play:count:{songId}这个 Redis key。Redis 这条增量作废。下一次定时任务不会再把旧增量刷进去。优点简单好实现。缺点如果删除 Redis 网络超时失败不一致仍然会发生。方案 3记录增量日志不要直接用 Redis 存最终增量数字。Redis 只记录变更。或者数据库新建一张增量日志表。每次播放除了 Redis 自增插入一条增量日志。定时任务读取日志表同步同步完标记已处理。就算 Redis 宕机数据库日志还留存记录不会丢数据。优点解决宕机丢数减少不一致风险。缺点每一次播放都插入数据库又增加数据库 IO违背最开始减轻数据库压力初衷。五、强一致 vs 最终一致如果业务强行要求强一致性该怎么办本项目 Redis 暂存增量定时同步只能保障最终一致性。若业务场景余额等要求强一致优先方案放弃 Redis 做计数缓冲读写直接访问 MySQL。牺牲一部分吞吐量换取数据准确。分布式事务 Seata 理论可实现事务回滚但是 Redis 不支持 XA 协议工程落地麻烦很少用于解决 Redis‑MySQL 一致性。六、思考总结“不存在优雅、高性能的方案让 Redis 与 MySQL 保证强一致性。工业上的思路是业务选型规避这个难题。如果要求强一致就不要把写逻辑交给 Redis如果想用 Redis 扛住高并发写压力就要接受最终一致性。”如果非要强一致又想要高性能可以换专门组件例如 Redis 本身的 Redisson 的 RLock 只是锁锁只能减少并发冲突锁解决不了网络故障导致双写不一致。锁≠强一致。