Redis 先排队,再在隔离窗口内执行命令;错误不代表自动撤销已完成写入。

Redis 事务把一组命令当作一个整体执行

Redis 事务先在一条连接上积累命令队列,再进入一个隔离的执行窗口。MULTI 开始排队,EXEC 按顺序执行已接受的命令。这里的关键保证是其它客户端的命令不能插进执行过程,而不是后面一条失败时,前面所有成功写入都能自动撤销。 入队与执行是两个阶段 QUEUED 表示服务端接受了命令,等待后续执行,并不表示这条命令想完成的写入已经成功。Redis 在接受命令时就会检查命令是否存在、参数数量是否正确;依赖当前数据的错误,例如向字符串键执行列表操作,则可能直到 EXEC 才暴露。不能笼统地把它们都称为语法错误,因为两种失败对应的队列处理方式并不相同。 在队列中发送 GET,同样先收到 QUEUED,真正的值出现在 EXEC 的结果数组里。客户端不能先读取这个排队 GET 的实际结果,再据此决定本次事务后面的命令。需要在应用内判断时,可先用 WATCH 保护读取依赖;必须在读取与写入之间分支时,可考虑有界的服务端脚本。 客户端缓冲又增加了一层。redis-py 的普通事务流水线先把命令放进本地列表,直到 execute 才发送 MULTI、各条命令与 EXEC。set 方法返回流水线对象,并不等于服务端已确认入队。下面使用专用连接读取原始响应,是为了观察协议的实际阶段,而不是把客户端的链式调用误当成服务器执行结果。 隔离从执行时开始 MULTI 不会替调用方提前锁住相关键。一个客户端仍在构造队列时,另一个客户端完全可以更新这些键。队列中的 GET 读取的是它执行时的值,不是 MULTI 开始时保存的快照;后面的 GET 也能看到本事务前面 SET 的写入。把不被插队说成启动时的一致快照,会误导依赖旧值的业务判断。 事务必须始终使用同一条连接,而且这条连接不能混入无关业务。如果连接池为 MULTI 和 EXEC 分别分配连接,它们就不属于同一个事务状态。应用代码应优先使用客户端提供的事务抽象;实验直接访问连接,只用于核验已固定版本的协议行为。 ...

三月 31, 2027 · 3 分钟 · XB Field Notes