Redis - 7, transaction operation

1. Redis transaction definition

Redis transaction is a separate isolation operation. All commands in the transaction will be serialized and executed sequentially. During the execution of the transaction, it will not be interrupted by command requests sent by other clients.

The main function of the redis transaction is to concatenate multiple commands to prevent other commands from jumping the queue.

2、Multi、Exec、discard

From the input of the Multi command, the input commands will enter the command queue in sequence, but will not be executed until the Exec is entered, and redis will execute the previous commands in sequence.

In the process of forming a team, you can give up the team by discarding.

Redis transactions are divided into two phases: team formation phase and execution phase

  • Teaming stage: just add all commands to the command queue
  • Execution phase: Execute the commands in the queue sequentially. During the execution of these commands, they will not be queued or interrupted by request commands sent by other clients.

2.1. Several related commands

2.1.1, multi: mark the beginning of a transaction block

Marks the start of a transaction block.

Multiple commands in the transaction block will be put into a queue in sequence, and finally executed atomically by the exec command.

example

redis> MULTI # 标记事务开始
OK
redis> INCR user_id # 多条命令按顺序入队,返回值为QUEUED,表示这个命令加入队列了,还没有被执行。
QUEUED
redis> INCR user_id
QUEUED
redis> INCR user_id
QUEUED
redis> PING
QUEUED
redis> EXEC         # 执行
1) (integer) 1
2) (integer) 2
3) (integer) 3
4) PONG

2.1.2, exec: Execute the commands in all transaction blocks

Executes the commands inside all transaction blocks.

If a certain (or certain) key is under the monitoring of the watch command, and there are commands related to this (or these) key in the transaction block, then the exec command can only be executed when the (or these) key is not controlled by other commands. Execute and take effect in the case of changes, otherwise the transaction is aborted.

return value:

The return values ​​of all commands in the transaction block are arranged in the order in which the commands are executed.
Returns nil when the operation is interrupted.

3 examples

# 示例1:事务被成功执行
redis> MULTI
OK
redis> INCR user_id
QUEUED
redis> INCR user_id
QUEUED
redis> INCR user_id
QUEUED
redis> PING
QUEUED
redis> EXEC
1) (integer) 1
2) (integer) 2
3) (integer) 3
4) PONG

# 示例2:监视 key,且事务成功执行
redis> WATCH lock lock_times
OK
redis> MULTI
OK
redis> SET lock "huangz"
QUEUED
redis> INCR lock_times
QUEUED
redis> EXEC
1) OK
2) (integer) 1

# 示例3:监视 key,且事务被打断
redis> WATCH lock lock_times
OK
redis> MULTI
OK
redis> SET lock "joe" # 就在这时,另一个客户端修改了 lock_times 的值
QUEUED
redis> INCR lock_times
QUEUED
redis> EXEC           # 因为 lock_times 被修改, joe 的事务执行失败
(nil)

2.1.3, discard: cancel the transaction

Cancel the transaction, abandoning the execution of all commands within the transaction block.

return value:

Always returns OK.

example

redis> MULTI
OK
redis> PING
QUEUED
redis> SET greeting "hello"
QUEUED
redis> DISCARD
OK

3. Transaction error handling

3.1, Situation 1: The order in the team is wrong, resulting in the cancellation of all orders

If an error report occurs for a command in the team, all commands in the entire queue will be canceled during execution.

 The sample code is as follows. Three set commands are executed in the transaction, but the third command set address command itself has a problem, and it fails to join the queue. When exec is finally executed, all commands are cancelled.

127.0.0.1:6379> flushdb
OK
127.0.0.1:6379> multi #开启一个事务块
OK
127.0.0.1:6379(TX)> set name ready
QUEUED
127.0.0.1:6379(TX)> set age 30
QUEUED
127.0.0.1:6379(TX)> set address #命令有问题,导致加入队列失败
(error) ERR wrong number of arguments for 'set' command
127.0.0.1:6379(TX)> exec #执行exec的时候,事务中所有命令都被取消
(error) EXECABORT Transaction discarded because of previous errors.

3.2, Situation 2: There is no problem in the team formation, and some successes and some failures during execution

There is no problem in the process of command teaming, and errors in execution will lead to partial success and partial failure.

 The sample code is as follows. There are 3 commands in the transaction, and all 3 commands are enqueued successfully. When the exec command is executed, commands 1 and 3 succeed, and the second one fails.

127.0.0.1:6379> multi
OK
127.0.0.1:6379(TX)> set k1 v1 #命令1:设置k1的值为v1
QUEUED
127.0.0.1:6379(TX)> incr k1 #命令2:k1的值递增1,由于k1的值不是数字,执行的时候会失败的
QUEUED
127.0.0.1:6379(TX)> set k2 v2 #命令3:设置k2的值为v2
QUEUED
127.0.0.1:6379(TX)> exec #执行命令,1和3命令成功,第2个失败了
1) OK
2) (error) ERR value is not an integer or out of range
3) OK
127.0.0.1:6379> mget k1 k2 #查看k1和k2的值
1) "v1"
2) "v2"

4. The problem of transaction conflict

4.1. Example

Imagine a scenario:

You only have 10,000 in your account, and multiple people use your account to participate in the Double Eleven snap-up at the same time.
One request wants to reduce the amount by 8,000.
One request wants to reduce the amount by 5,000.
One request wants to reduce the amount by 1,000.

 Three requests come to bring ① at the same time, and the balance seen is 10000, which is greater than the operation amount, and the operation of modifying the balance is performed, and finally the amount becomes -4000, which is obviously problematic.

4.2, pessimistic lock

 Pessimistic Lock (Pessimistic Lock), as the name suggests, is very pessimistic. Every time you go to get the data, you think that others will modify it, so every time you get the data, you will lock it, so that others will block the data until it gets it. to the lock. Many such locking mechanisms are used in traditional relational databases, such as row locks, table locks, read locks, write locks, etc., all of which are locked before operations are performed.

4.3 Optimistic locking

Optimistic Lock, as the name suggests, is very optimistic. Every time I go to the data, I think that others will not modify it, so it will not be locked, but when modifying, I will judge whether others have updated it during this period. Data, you can use mechanisms such as version numbers. Optimistic locking is suitable for multi-read application types, which can improve throughput. Redis uses this check-and-set mechanism to implement transactions.

4.4、watch key [key ...]

Before executing multi, first execute watch key1 [key2 ...] to monitor one or more keys. If the values ​​corresponding to these keys are changed by other commands before the exec command of the transaction, all commands in the transaction will be Interrupted, that is, all operations of the transaction will be cancelled.

example

Open two windows, execute the corresponding commands in different windows according to the time points in the table below, and pay attention to the results.

time window 1 window 2
T1 flushdb
T2 set balance 100
T3 watch balance
T4 multi
T5 set name ready incrby balance 50
T6 incrby balance 10 get balance
T7 exec
Q8 get balance
T9 get name

In window 1, the balance is monitored, that is to say, after executing the watch balance command and before the exec command, if there are other requests to modify the balance, then all commands in the window 1 transaction will be cancelled.

After window 1 watch balance, because window 2 has modified the balance at time T5, all commands of transactions in window 1 will be cancelled.

The execution results of window 1 are as follows

127.0.0.1:6379> flushdb #清空db,方便测试
OK
127.0.0.1:6379> set balance 100 #设置balance的值为100
OK
127.0.0.1:6379> watch balance #监视balance,若balance在事务阶段被其他命令修改,事务执行将被取消
OK
127.0.0.1:6379> multi #开启事务
OK
127.0.0.1:6379(TX)> set name ready #设置name的值为ready
QUEUED
127.0.0.1:6379(TX)> incrby balance 10 #将balance的值+10
QUEUED
127.0.0.1:6379(TX)> exec #执行事务,由于balance被窗口2修改了,所以本事务执行失败,返回nil
(nil)
127.0.0.1:6379> get balance #获取balance,原始值为100,被窗口2加了50,结果为150
"150"
127.0.0.1:6379> get name #获取name的值,事务中set name 未成功,所以name没有
(nil)

Window 2 execution result

127.0.0.1:6379> incrby balance 50 #balance原子+50
(integer) 150
127.0.0.1:6379> get balance #获取balance的值,为150
"150"

4.5, unwatch: cancel monitoring

Cancel the monitoring of all keys by WATCH command.

If the EXEC command or the DISCARD command is executed first after executing the WATCH command, then it is not necessary to execute UNWATCH.

Because the EXEC command will execute the transaction, the effect of the WATCH command has already been produced; while the DISCARD command cancels the transaction and also cancels all monitoring of the key, so after these two commands are executed, there is no need to execute UNWATCH.

redis> WATCH lock lock_times
OK
redis> UNWATCH
OK

5. Three characteristics of redis transaction

5.1. Separate isolation operation

All commands in the transaction will be serialized and executed sequentially. During the execution of the transaction, it will not be interrupted by command requests sent by other clients.

5.2. There is no concept of isolation level

The commands in the queue will not be actually executed until they are submitted (exec), because any instructions will not be actually executed before the transaction is committed.

5.3. Atomicity cannot be guaranteed

If a command fails to execute in the transaction, subsequent commands will still be executed without rollback.

If one of the commands fails in the team formation phase, none of them will succeed later; if it succeeds in the team formation phase, if any command fails in the execution phase, it will fail, and other commands will be executed normally, and there is no guarantee that all of them will succeed or not. All fail.

Guess you like

Origin blog.csdn.net/qq_34272760/article/details/125393110