Open In App

Complete tutorial of Transactions in Redis

Redis transactions allow you to group multiple commands into a single atomic operation. An atomic operation means that all the commands within a transaction are executed together, ensuring that either all of them succeed or none of them do. Redis transactions use a concept called “MULTI/EXEC” to initiate and commit the transaction.



Syntax:

MULTI

<Redis commands>



EXEC

Commands:

1. MULTI:

The MULTI command in Redis is used to start a transaction. Transactions in Redis allow you to group multiple commands together and ensure that they are executed atomically. This means that if any command within the transaction fails for any reason, all the commands are discarded, and nothing is executed. This ensures data integrity and consistency in Redis.

Syntax:

MULTI

How the MULTI command works?

Example:

MULTI # Start a transaction
SET name “Alice” # Queue the SET command
HSET user:123 username “Alice” # Queue the HSET command
RPUSH queue1 “item1” # Queue the RPUSH command

Explanation:

  • We start a transaction with MULTI.
  • We queue multiple Redis commands (SET, HSET, and RPUSH) inside the transaction. These commands are not executed immediately but are saved for later execution.
  • The transaction is now in progress, and Redis is in a “queued” state.
  • To execute the queued commands and make them take effect, you need to use the EXEC command. If you want to cancel the transaction without executing any of the queued commands, you can use the DISCARD command.

2. EXEC:

The EXEC command in Redis is used to execute a group of commands that have been previously queued as part of a transaction using the MULTI command. It is a fundamental part of Redis transactions and ensures that all the queued commands are executed atomically, either all at once or none at all. Here’s a detailed explanation of the EXEC command:

Syntax:

EXEC

How the EXEC Command works?

Example:

MULTI # Start a transaction
SET name “Alice” # Queue the first command
HSET user:123 username “Alice” # Queue the second command
RPUSH queue1 “item1” # Queue the third command
EXEC # Execute the transaction

Explanation:

  • We start a transaction with MULTI and queue three commands.
  • When we issue EXEC, Redis executes all three commands atomically.
  • If any of these commands had failed due to an error, the entire transaction would have been discarded.

Error Handling: It’s important to note that Redis will queue all the commands inside a transaction even if some of them have errors. Errors are not raised until the EXEC command is issued. If any command encounters an error during execution, the entire transaction will be aborted, and none of the changes will be applied.

3. DISCARD Command:

The DISCARD command is used to cancel a transaction that is currently in progress. It discards all the commands that were queued in the transaction, and the Redis server will exit the transaction mode. If no transaction is in progress, DISCARD has no effect.

Syntax:

DISCARD

Example:

127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> SET key1 “value1”
QUEUED
127.0.0.1:6379> SET key2 “value2”
QUEUED
127.0.0.1:6379> DISCARD
OK

In this example, the MULTI command starts a transaction, followed by two SET commands. However, before calling EXEC to execute the transaction, the DISCARD command is used, which cancels the transaction, and no changes are made to the keys.

4. UNWATCH Command:

The UNWATCH command is used to cancel the WATCH on all keys previously set using the WATCH command. It is commonly used in the context of optimistic locking in distributed systems.

Syntax:

UNWATCH

How UNWATCH command works?

Behavior of UNWATCH:

Example:

127.0.0.1:6379> WATCH key1 key2
OK
127.0.0.1:6379> SET key1 “value1”
OK
127.0.0.1:6379> UNWATCH
OK

In this example, the WATCH command sets a watch on two keys, key1 and key2. If any other client modifies these keys before a transaction is executed, the transaction will be aborted. The UNWATCH command cancels the watch on those keys.

5. WATCH Command:

The Redis WATCH command is used in conjunction with transactions to implement optimistic locking. It allows you to monitor one or more keys for changes. If any of the watched keys are modified by another client before the transaction is executed, the transaction will fail, and none of the commands within the transaction will be executed. This ensures that the transaction is only executed when the watched keys remain unchanged by other clients.

Syntax:

WATCH key [key …]

How WATCH command works?

Behavior of WATCH command:

Example:

127.0.0.1:6379> WATCH key1 key2
OK
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> SET key1 “value1”
QUEUED
127.0.0.1:6379> SET key2 “value2”
QUEUED
127.0.0.1:6379> EXEC
(nil)

Explanation:

  • The WATCH command sets a watch on key1 and key2.
  • After that, a transaction is initiated using the MULTI command, and two SET commands are queued.
  • However, if any other client modifies key1 or key2 before EXEC is called, the transaction will be aborted, and the EXEC will return nil.

Use Cases of WATCH command:

Example:

Here we want to transfer money between two Redis keys representing the balances of two users:

127.0.0.1:6379> SET user1_balance 100;
OK
127.0.0.1:6379> SET user2_balance 50
OK

Now, let’s perform the transaction to transfer 20 units from “user1_balance” to “user2_balance”:

127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> DECRBY user1_balance 20
QUEUED
127.0.0.1:6379> INCRBY user2_balance 20
QUEUED
127.0.0.1:6379> EXEC
1) (integer) 80 # Result of DECRBY operation on user1_balance
2) (integer) 70 # Result of INCRBY operation on user2_balance

Explanation:

What is a command queue and how to discard it?

A command queue in the context of Redis transactions refers to a list of commands that have been queued up to be executed as part of a transaction. When you initiate a Redis transaction using the MULTI command, any subsequent commands are placed in this queue, awaiting the final execution using the EXEC command. This allows you to group multiple commands together and ensure that they are executed atomically, maintaining data consistency.

Below is the working of command queue in Redis transactions:

Discarding the Command Queue:

If something goes wrong before the EXEC command is issued and you decide not to proceed with the transaction, you can use the DISCARD command to discard the entire command queue. The DISCARD command resets Redis to its non-transactional state, and all the commands in the queue are discarded.

Syntax:

DISCARD

Example:

MULTI
SET key1 value1
SET key2 value2
DISCARD

Note: If you choose to discard the transaction using the DISCARD command, the changes made by the SET commands to key1 and key2 will not take effect, as the entire command queue is discarded.

Implementation of optimistic locking using check and set

Optimistic Locking and Check and Set (CAS):

Optimistic locking is a technique used to handle concurrent updates in a distributed system. The idea is to allow multiple clients to read data concurrently, and when they want to update the data, they first check if the data has been modified by any other client before proceeding with the update.

The Check and Set (CAS) pattern is a common method for implementing optimistic locking. It involves the following steps:

Implementing Optimistic Locking using WATCH and CAS in Redis:

In Redis, you can implement optimistic locking using the WATCH command along with a transaction. Here’s is the steps to implement optimistic locking using WATCH AND CAS in Redis:

Remember, optimistic locking using CAS is a powerful way to handle concurrency, but you should carefully design your application’s logic and error handling to ensure data consistency and proper user experience in case of conflicts. It’s important to note that Redis transactions do not support rollback like traditional relational database transactions. If an error occurs during the execution of a transaction, you will need to handle the error and revert any side effects manually.


Article Tags :