As a very important basic function in relational database, transaction, how is handled and used in Redis?

1. Introduction

Transactions refer to providing a mechanism to package multiple commands, execute them sequentially at once, and ensure that the server does not continue to process other commands from the client until all of the commands in the transaction have been executed.

Transactions are also a very important capability required for other relational databases. Take the payment scenario as an example. Normally, the account balance is subtracted only after the normal consumption is completed. But if there is no transaction protection, there may be consumption failure, but the account balance will still be deducted, I think this situation should not be acceptable to anyone, right? So transaction is a very important basic function in database.

2. Basic use of transactions

Transactions in other languages are generally divided into the following three phases:

  • Start transactions — Begin Transaction
  • Execute the business code and commit the Transaction — Common Transaction
  • Rollback Transaction If an exception occurs in the service processing

Take transaction execution in Java as an example:

// Start the transaction
begin();
try {
    / /...
    // Commit the transaction
    commit();
} catch(Exception e) {
    // Rollback the transaction
    rollback();
}
Copy the code

Transactions in Redis also go through three phases from start to finish:

  • Open the transaction
  • The command shown
  • Execute transaction/abandon transaction

The multi command is used to start a transaction, the exec command is used to execute a transaction, and the discard command is used to abandon a transaction.

1) Start the transaction

The multi command is used to start a transaction. The code is as follows:

> multi
OK
Copy the code

The multi command can change the client from non-transaction mode to transaction mode, as shown in the following figure:

Pay attention to
multi

(error) ERR MULTI calls can not be nested

The result is shown in the following code:

127.0.0.1:6379> multi
OK
127.0.0.1:6379> multi
(error) ERR MULTI calls can not be nested
Copy the code

When the client is in a non-transactional state, using multi command will return the result OK. If the client is already in a transactional state, running multi command will result in multi command cannot be nested error, but will not terminate the client in a transactional state, as shown in the following figure:

2) Add the command to the column

After the client enters the transaction state, all the normal Redis operation commands executed (those that do not trigger transaction execution or abandonment and cause queue exception) will be entered in sequence, and QUEUED will be returned when the command is successfully entered, as shown in the following code:

> multi
OK
> set k v
QUEUED
> get k
QUEUED
Copy the code

The execution process is as follows:

Pay attention to

3) Execute transaction/abandon transaction

The command to execute a transaction is exec, and the command to discard a transaction is discard. Example code for executing a transaction is as follows:

> multi
OK
> set k v2
QUEUED
> exec
1) OK
> get k
"v2"
Copy the code

Example code for abandoning a transaction is as follows:

> multi
OK
> set k v3
QUEUED
> discard
OK
> get k
"v2"
Copy the code

The execution process is as follows:

3. Transaction error & rollback

Errors in transaction execution fall into the following three categories:

  • Errors that only occur during execution (referred to as “runtime errors”);
  • An error when entering a column does not terminate the entire transaction;
  • Column entry error will terminate the entire transaction.

1) Error during execution

Example code is as follows:

> get k
"v"
> multi
OK
> set k v2
QUEUED
> expire k 10s
QUEUED
> exec
1) OK
2) (error) ERR value is not an integer or out of range
> get k
"v2"
Copy the code

The command interpretation is as follows:

2) Entry errors do not affect transactions

Example code is as follows:

> get k
"v"
> multi
OK
> set k v2
QUEUED
> multi
(error) ERR MULTI calls can not be nested
> exec
1) OK
> get k
"v2"
Copy the code

The command interpretation is as follows:

multi
multi
watch
watch

3) The transaction ends due to an entry error

Example code is as follows:

> get k
"v2"
> multi
OK
> set k v3
QUEUED
> set k
(error) ERR wrong number of arguments for 'set' command
> exec
(error) EXECABORT Transaction discarded because of previous errors.
> get k
"v2"
Copy the code

The command interpretation is as follows:

4) Why not support transaction rollback?

Redis official documentation explains as follows:

If you have a relational databases background, the fact that Redis commands can fail during a transaction, but still Redis will execute the rest of the transaction instead of rolling back, may look odd to you. However there are good opinions for this behavior:

  • Redis commands can fail only if called with a wrong syntax (and the problem is not detectable during the command queueing), or against keys holding the wrong data type: this means that in practical terms a failing command is the result of a programming errors, and a kind of error that is very likely to be detected during development, and not in production.
  • Redis is internally simplified and faster because it does not need the ability to roll back. An argument against Redis point of view is that bugs happen, however it should be noted that in general the roll back does not save you from programming errors. For instance if a query increments a key by 2 instead of 1, or increments the wrong key, there is no way for a rollback mechanism to help. Given that no one can save the programmer from his or her errors, and that the kind of errors required for a Redis command to fail are unlikely to enter in production, we selected the simpler and faster approach of not supporting roll backs on errors.

The author does not support transaction rollback for two reasons:

  • In his view, Redis transaction execution errors are usually the result of programming errors that occur only in the development environment and rarely in the actual production environment, so he sees no need to develop transaction rollback capabilities for Redis.
  • Transaction rollback is not supported because this complexity is incompatible with Redis’s simple and efficient design.

Transaction rollback is not supported, which means that a transaction rollback is not supported for runtime errors.

4. Monitor

The watch command is used to provide an optimistic lock (CAS, Check And Set) for a transaction in the case of client concurrency. In other words, the watch command can be used to monitor one or more variables. If a monitoring item is modified during a transaction, the whole transaction will terminate. The basic syntax of watch is as follows:

watch key [key …]

The watch sample code is as follows:

> watch k
OK
> multi
OK
> set k v2
QUEUED
> exec
(nil)
> get k
"v"
Copy the code

As you can see from the above commands, if exec returns nil, it means that the object monitored by Watch was modified during the transaction execution. The result of get K also shows that the value set in the transaction, set k v2, did not execute properly. The execution process is as follows:

Pay attention to
watch
watch

> multi
OK
> set k v3
QUEUED
> watch k
(error) ERR WATCH inside MULTI is not allowed
> exec
1) OK
> get k
"v3"
Copy the code

The command interpretation is as follows:

unwatch
unwatch

> set k v
OK
> watch k
OK
> multi
OK
> unwatch
QUEUED
> set k v2
QUEUED
> exec
1) OK
2) OK
> get k
"v2"
Copy the code

As you can see, even if the value of k is changed during the execution of the transaction, the whole transaction will still execute smoothly because the unwatch command is called.

5. Transactions are used in programs

Here’s how transactions are used in Java:

import redis.clients.jedis.Jedis;
import redis.clients.jedis.Transaction;

public class TransactionExample {
    public static void main(String[] args) {
        // Create a Redis connection
        Jedis jedis = new Jedis("xxx.xxx.xxx.xxx".6379);
        // Set the Redis password
        jedis.auth("xxx");
        // Set the key value
        jedis.set("k"."v");
        // Enable monitor watch
        jedis.watch("k");
        // Start transaction
        Transaction tx = jedis.multi();
        // The command is entered
        tx.set("k"."v2");
        // Execute a transaction
        tx.exec();
        System.out.println(jedis.get("k")); jedis.close(); }}Copy the code

6. Summary

Transactions provide a mechanism for multiple commands to be executed sequentially at once. There are five commands related to Redis transactions:

  • Multi: enables a transaction
  • Exec: Executes a transaction
  • Discard: discards a transaction
  • Watch: Provides an optimistic lock implementation for transactions
  • Unwatch: Unmonitor (unlock optimistic locks in transactions)

Normally, a Redis transaction is divided into three phases: start transaction, command entry, and transaction execution. Redis transactions do not support transaction rollback for run-time errors, but do provide transaction rollback if certain enrolling errors such as set key or watch monitoring items are modified.

7. There is

How to solve the problem of concurrent modification in Redis transaction? Does Redis support transaction rollback? What are the three errors that occur when using Redis transactions? How do these three errors affect transactions? How many questions can you answer that only an expert can answer correctly?

8. Reference & acknowledgements

Redis. IO/switchable viewer/tran…

Redisbook. Readthedocs. IO/en/latest/f…

Follow the QR code below and subscribe for more exciting content