A transaction in a database can be defined as a logical unit of work that contains two or more operations to be executed. A transaction usually involves several operations such as inserting, updating, and deleting data, and typically ensures data consistency and integrity in multi-step operations that involve multiple database changes. Transactions are either committed, meaning all the changes made during the transaction are saved to the database, or discarded, meaning none of the changes made during the transaction are saved. Some databases have a rollback feature such that when an error occurs in one of the operations in a transaction, the database is returned to the state it was in before the transaction began.
Let’s see the examples of transactions in the Redis database.
In Redis, a transaction is a group of commands that are executed as a single atomic operation. It provides a mechanism for ensuring that all the commands in the transaction are executed together or not at all. Redis transactions are based on a concept called MULTI/EXEC. To perform a transaction in Redis, the MULTI
command is used first which indicates the beginning of the transaction. After that, multiple commands can now be sent to Redis. These commands would be stored temporarily or buffered instead of being executed immediately. The EXEC
keyword initiates the processing of the commands.
As mentioned, Redis transactions are based on the MULTI/EXEC concept, and there are several keywords that are associated with Redis transactions. These keywords are used to ensure data consistency and atomicity during Redis transactions. Here is the list of these keywords:
MULTI
: This keyword is used to start a transaction block in Redis. After the MULTI
command is executed, all the subsequent commands will be queued and executed as a single, atomic transaction.
EXEC
: This keyword is used to execute all the commands that have been queued up in a transaction block. Once EXEC
is executed, Redis will execute all the commands in the transaction block as a single, atomic transaction.
DISCARD
: This keyword is used to discard all the commands that have been queued up in a transaction block. If a user decides to cancel a transaction, they can use the DISCARD
command to undo all the changes that have been queued so far.
WATCH
: This keyword is used to monitor one or more keys for modifications during a transaction. If any of the watched keys are modified by another client during the transaction, the transaction will be automatically aborted.
UNWATCH
: This keyword is used to unwatch all the keys that have been previously watched during a transaction.
Take a banking application, for instance. If a user wants to transfer money from one account to another, the following sequential events occur:
Deduct the amount to be transferred from account A
Add the amount to account B.
Depending on the system implemented, there might be other operations that occur besides these two, but that’s not the focus of this Answer.
To commit a transaction in Redis, we need to follow the following instructions in the Redis CLI or terminal:
Initialize the transaction using the MULTI
keyword.
MULTI
In the Redis terminal, when a transaction is initialized successfully, Redis returns OK
and adds the (TX)
flag to the prompt.
Set the required test variables.
SET accountA 100SET accountB 200
In the terminal, we will have a QUEUED
message. This indicates that the result of the operation has not been committed to memory.
Perform the transaction by deducting 50 units from A and adding them to B.
DECRBY accountA 50INCRBY accountB 50
To commit this transaction to memory, we use EXEC
command.
EXEC
Redis transactions queue a series of operations together and execute them sequentially.
To get hands-on experience with all the commands above, all commands can be copied and run in the terminal widget below:
The use of the DISCARD
command is similar to the use of EXEC
. The difference is in their function. The DISCARD
command is used to do away with all the operations that have been queued up.
MULTISET accountA 100SET accountB 200DECRBY accountA 50INCRBY accountB 50DISCARD
The WATCH
command is used to monitor one or more keys for modifications. It marks the keys for watching and prevents any transaction from executing if any of the watched keys have been modified by another client. If any of the watched keys are modified, the transaction will be aborted, and the application can retry the transaction. This would prevent race conditions.
WATCH accountA accountBMULTISET accountA 100SET accountB 200DECRBY accountA 50INCRBY accountB 50EXEC
The WATCH
command is particularly useful in cases where multiple clients are accessing the same keys, and there is a possibility of race conditions. For example, in our banking application, where multiple users can transfer money between the same accounts simultaneously. In such cases, WATCH
can help prevent inconsistencies in the data and ensure that the transactions are executed reliably.
Redis transactions differ from regular database transactions in a few ways.
Redis transactions are not ACID-compliant, which means they do not provide the same level of consistency and reliability as traditional database transactions.
Redis transactions also do not support rollback, which means that once a transaction is committed, its effects are permanent and cannot be undone.
It is important to know that these are design decisions. Redis is an in-memory database that boasts speed. According to the official documentation, “Redis does not support rollbacks of transactions since supporting rollbacks would have a significant impact on the simplicity and performance of Redis.”
Despite these limitations, Redis transactions are still very useful.
Transactions in Redis are a powerful way to execute simultaneous commands in one operation. This ensures that all the commands are executed or none of them are which helps in managing database shortcomings and consistency in data. With everything considered, transactions are a valuable feature of Redis for managing operations that involve multiple commands that need to be executed at once.