Redis Transactions
This page provides an Introduction to Redis Transactions. These are my notes from the RU101 Redis University course.
Redis Transactions
Redis transactions ensure that all commands in a transaction are serialized and executed sequentially, ensuring isolation and atomicity. Commands queued during a transaction are isolated and private. Other sessions cannot see the changes until the transaction is executed.
Redis does not support nested transactions because commands are queued instead of immediately executed, reducing the need for nested operations.
Below are the commands used to control transactions in Redis
MULTI
Starts the transaction, queuing up subsequent commands for execution.
EXEC
Executes the queued commands.
DISCARD
Discards the queued commands.
Below is an example flow for the transaction
Client 1: Sets a key event:Judo to "Sold Out".
SET event:Judo "Sold Out"
OK
Client 2: Starts a transaction using MULTI and queues commands (SET and INCR), but these commands are not executed immediately.
MULTI
OK
SET event:Judo 100
QUEUED
INCR event:Judo
QUEUED
Client 1: Performs a GET operation, still seeing the value "Sold Out" since client 2's commands are only queued.
GET event:Judo
"Sold Out"
Client 2: Queues a GET command, which is also not executed immediately.
GET event:Judo
Client 2: Executes EXEC, the queued commands are executed as a batch, changing the value of the key from 100 to 101. The final GET command returns 101.
EXEC
1) OK
2) (integer) 101
3) "101"
Client 1: Performs a GET operation, and will see updated value.
GET event:Judo
101
Handling Errors
-
If an invalid command is queued, Redis marks the transaction as invalid, and none of the commands will be executed upon EXEC.
-
If a valid command causes a failure, like performing INCR on a list data type, Redis will continue executing the remaining commands.
-
Redis does not support rollback to optimize performance. Programming errors should be addressed in pre-production cycles.
Optimistic Concurrency Control
Optimistic locking or optimistic concurrency control is a mechanism that allows you to specify an interest in an object and get a notification if that object has changed. Keyspace notifications is the mechanism that can be used in Redis to satisfy this need.
Below are the commands for implmenting optimistic concurrency control in Redis.
WATCH
WATCH is used to declare interest in one or more keys. When EXEC is called the transaction will fail if any watched keys have been modified.
WATCH has to be called before the transaction is started, so you need to decide upfront the keys that need to be observed. Multiple WATCH commands can be executed before the MULTI. The effects are cumulative. Subsequent WATCH commands do not override previous keys being watched.
Watches are also local to the current client and connection. They are not global in scope. Only clients with the watch on a specific key will fail.
UNWATCH
UNWATCH is used to remove all watch keys. If a transaction is successfully completed with EXEC then all keys are automatically unwatched. You do not need to explicitly unwatch the keys in your code after a successful transaction.
Successful Transaction
Below is an example of successful transaction scenario using WATCH and UNWATCH.
Client 1: Watches the key event:Judo with a value of 200
WATCH event:Judo
OK
Client 1: starts a transaction, modifies the key to 101, and calls EXEC.
MULTI
OK
SET event:Judo 101
QUEUED
GET event:Judo
"101"
Since the key has not been modified by another client, the transaction succeeds, and the key is set to 101.
Unsuccessful Transaction
Below is an example of unsuccessful transaction scenario using WATCH and UNWATCH.
Client 1: watches the key event:Judo and starts a transaction to increment its value.
WATCH event:Judo
OK
MULTI
OK
INCR event:Judo
QUEUED
Client 2: Changes the key value to 100 by decrementing it.
DECR event:Judo
(integer) 100
Client 1: Calls EXEC, which fails with a nil response because the watched key has been modified. The transaction is discarded.
EXEC
(nil)