Redis transaction in-depth analysis and use

1. Preface

Transaction refers to providing a mechanism to package multiple commands and execute them sequentially at one time, and ensuring that the server will continue to process other commands of this client only after executing all commands in the transaction.

Transaction is also a very important capability required by other relational databases. Take the payment scenario as an example. Under normal circumstances, the account balance will be deducted only after the normal consumption is completed. However, without transaction protection, consumption failure may occur, but the balance of the account will still be deducted. I think this situation should be unacceptable to anyone? Therefore, transaction is a very important basic function in database.

2. Basic transaction usage

In other languages, transactions are generally divided into the following three stages:

Take transaction execution in Java as an example:

// 开启事务
begin();
try {
    //......
    // 提交事务
    commit();
} catch(Exception e) {
    // 回滚事务
    rollback();
}

Transactions in redis also go through three stages from beginning to end:

Among them, 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 discard a transaction.

1) Open transaction

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

> multi
OK

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

The execution effect 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

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

2) Command listing

After the client enters the transaction state, all conventional redis operation commands executed (commands that do not trigger transaction execution or abandon and cause listing exceptions) will be listed in turn. After the command is listed successfully, it will return queued, as shown in the following code:

> multi
OK
> set k v
QUEUED
> get k
QUEUED

The execution process is shown in the figure below:

3) Execute transaction / discard transaction

The command to execute a transaction is exec, and the command to abandon a transaction is discard. The example code of executing a transaction is as follows:

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

The example code of discarding a transaction is as follows:

> multi
OK
> set k v3
QUEUED
> discard
OK
> get k
"v2"

The execution process is shown in the figure below:

3. Transaction error & rollback

Errors in transaction execution are divided into the following three categories:

1) Error during execution

The 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"

The execution command is explained as follows:

2) A enlistment error does not cause the transaction to end

The 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"

The execution command is explained as follows:

3) A enlistment error causes the transaction to end

The 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"

The execution command is explained as follows:

4) Why is transaction rollback not supported?

The official redis document is explained as follows:

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.

Generally speaking, the author does not support transaction rollback for the following two reasons:

Transaction rollback is not supported here, which means that transaction rollback with runtime errors is not supported.

4. Monitoring

The watch command is used to provide an optimistic lock (CAS, check and set) for transactions when the client is concurrent, that is, you can use the watch command to monitor one or more variables. If a monitoring item is modified during the transaction, the whole transaction will terminate. The basic syntax of watch is as follows:

The sample code of watch is as follows:

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

As can be seen from the above commands, if the result returned by exec is nil, it means that the object monitored by watch has been modified during transaction execution. It can also be seen from the result of get k that the value set K V2 set in the transaction is not executed normally. The execution process is shown in the figure below:

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

The execution command is explained as follows:

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

It can be seen that even if the K value is modified during the execution of the transaction, the whole transaction will still execute smoothly because the unwatch command is called.

5. Use of transactions in procedures

The following is the use of transactions in Java. The code is as follows:

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

public class TransactionExample {
    public static void main(String[] args) {
        // 创建 Redis 连接
        Jedis jedis = new Jedis("xxx.xxx.xxx.xxx",6379);
        // 设置 Redis 密码
        jedis.auth("xxx");
        // 设置键值
        jedis.set("k","v");
        // 开启监视 watch
        jedis.watch("k");
        // 开始事务
        Transaction tx = jedis.multi();
        // 命令入列
        tx.set("k","v2");
        // 执行事务
        tx.exec();
        System.out.println(jedis.get("k"));
        jedis.close();
    }
}

6. Summary

Transactions provide a one-time sequential execution mechanism for multiple commands. There are five commands related to redis transactions:

Normally, redis transactions are divided into three stages: starting transactions, listing commands, and executing transactions. Redis transactions do not support transaction rollback with runtime errors, but provide the function of rolling back the whole transaction when some listing errors, such as set key or watch monitoring items, are modified.

7. Thinking questions

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

8. Reference & acknowledgment

https://redis.io/topics/transactions

https://redisbook.readthedocs.io/en/latest/feature/transaction.html#id3

The content of this article comes from the network collection of netizens. It is used as a learning reference. The copyright belongs to the original author.
THE END
分享
二维码
< <上一篇
下一篇>>