Transactions
Redis transactions batch commands with MULTI/EXEC — all queued commands run sequentially without interleaving from other clients.
Introduction
Redis transactions batch commands with MULTI/EXEC — all queued commands run sequentially without interleaving from other clients. Unlike SQL, there is no rollback if a command fails mid-EXEC; errors are per-command in the reply array.
WATCH implements optimistic locking — if a watched key changes before EXEC, the transaction aborts (EXEC returns nil). Use when contention is low and retry is cheap.
For conditional logic (if balance >= amount then debit), prefer Lua — MULTI cannot branch on read results.
Understanding the topic
Key concepts
- MULTI — start queue; commands return QUEUED.
- EXEC — run all queued atomically.
- DISCARD — abort queue.
- WATCH keys — optimistic lock; abort EXEC if changed.
- No rollback on command error inside EXEC.
- Pipeline ≠ transaction — pipeline has no atomicity guarantee.
sequenceDiagramClient->>Redis: WATCH keyClient->>Redis: MULTIClient->>Redis: commandsClient->>Redis: EXEC
Step-by-step explanation
- Client sends WATCH (optional) then MULTI.
- Subsequent commands queued until EXEC.
- On EXEC, WATCH checked; if OK all commands run.
- Other clients blocked only during EXEC instant — not during queue.
- UNWATCH clears watch list.
Syntax reference
Common commands
- EXEC nil — retry from WATCH.
- Don't mix WATCH with long client-side logic.
- Use Lua for read-modify-write with conditions.
WATCH account:42val = GET account:42MULTIDECRBY account:42 50INCRBY account:99 50EXEC# nil if account:42 changed between WATCH and EXEC
Informative example
Transfer credits with WATCH — retry loop on conflict:
# Pseudocode pattern in redis-cli sessionWATCH wallet:1GET wallet:1MULTIDECRBY wallet:1 10INCRBY wallet:2 10EXEC
In production services use Lua script or Redis 8+ alternatives for cleaner atomic transfer with balance check.
Real-world use
Real-world use cases
- Multi-key atomic update — inventory + order count.
- Optimistic concurrency on low-contention counters.
- Batch related writes in one EXEC.
- Pub/sub NOT triggered by transaction commands until EXEC.
- Pair with WATCH for compare-and-swap pattern.
Best practices
- Keep transactions short — few commands.
- Retry on EXEC nil with backoff.
- Prefer Lua for conditional multi-step logic.
- Don't WATCH hot keys at high contention.
- Document that errors don't rollback siblings.
- Use DISCARD on client timeout paths.
Common mistakes
- Expecting SQL-style rollback.
- Long work between WATCH and EXEC.
- Using MULTI for unrelated bulk load — use pipeline.
- WATCH on keys you don't modify — false aborts.
Advanced interview questions
Q1BeginnerMULTI/EXEC guarantee?
Q2BeginnerRollback on error?
Q3IntermediateWATCH purpose?
Q4IntermediateTransaction vs pipeline?
Q5AdvancedDebit only if sufficient balance?
Summary
MULTI/EXEC = atomic batch, no rollback.