Redis事务不是ACID事务,无隔离性、不支持回滚、不保证原子性;@Transactional对Redis无效,因缺乏对应PlatformTransactionManager;真正强一致场景应选Lua脚本、分布式锁或回归数据库。

Redis 事务在 Spring Boot 中“不生效”,不是 bug,而是它根本就不是你理解的 ACID 事务 —— 它没有隔离性、不支持回滚、也不保证原子性(只保证命令入队顺序执行)。
Redis 的 multi/exec 只是命令打包,不是事务
Spring Data Redis 提供的 RedisTemplate.execute(RedisCallback) 或 @Transactional 注解对 Redis **完全无效**。因为:
-
@Transactional是 Spring 对DataSource(如 JDBC)事务管理器的抽象,而 Redis 没有PlatformTransactionManager实现来支撑声明式事务 - Redis 的
MULTI命令只是把后续命令缓存进队列,EXEC才依次执行;中间任意命令报错(比如INCR作用于字符串),其他命令照常运行 —— 不会自动回滚 - 没有锁、没有 MVCC、没有事务日志,多个客户端并发执行
MULTI/EXEC块时,彼此之间完全无隔离
为什么加了 @Transactional 看起来“没反应”
你在 Redis 操作方法上写 @Transactional,Spring 启动时不会报错,但运行时它压根不会介入 —— 因为默认配置下,Spring 找不到能管 Redis 的事务管理器。
- 除非你手动注册一个
RedisTransactionManager(仅限 Spring Data Redis 2.x 且使用 Lettuce +enableTransactionSupport = true),但它只提供“连接绑定”语义,不是真正事务 - 即使启用了,它也只做到:在
multi()到exec()期间复用同一个连接,避免命令被分散到不同连接 —— 这和 MySQL 的事务提交/回滚毫无关系 - 常见误判:看到
redisTemplate.multi()被调用,就以为事务开始了;其实那只是一次客户端侧的命令缓冲操作
真正需要“原子+一致”时,该用什么替代
当业务要求类似“查库存 → 扣减 → 记录订单”强一致性时,别指望 MULTI/EXEC,得换思路:
- 用 Lua 脚本:所有逻辑写在一个脚本里,由 Redis 单线程原子执行,失败时整个脚本不生效(注意:Lua 里不能抛异常,要用
redis.call()的返回值判断) - 用分布式锁(如
RedisLockRegistry或 Redlock)配合常规操作:先抢锁,再查、改、存,最后释放锁 —— 但要注意锁超时与业务执行时间匹配 - 用消息队列 + 补偿:Redis 只做轻量缓存或预扣减,最终一致性靠下游 MQ 消费落库,并通过定时任务核对与修复
- 关键路径回归数据库:库存、订单等核心状态,仍应以 MySQL/PostgreSQL 为主存储,Redis 仅作加速层;事务保障交给关系型数据库
最容易被忽略的一点:很多团队在压测时发现 Redis MULTI/EXEC “好像生效了”,是因为并发低、没触发竞态;一旦流量上来,超卖、重复扣减立刻暴露 —— 它从设计上就不解决这类问题。


















