Redis transactions and locks

table of Contents

Why do we need transactions and locks?

In actual application scenarios, usually an operation will be accompanied by two or more data changes, such as the "payment" operation. At least one account's amount data will need to be reduced, and the other account's amount data will need to increase. Two operations. The transaction is used to operate multiple pieces of data in sequence, and will not be interrupted by other commands.

In the case of high parallelism, there are often multiple requests that operate on the same piece of data at the same time. How to ensure that the data is correct and only successfully operated by one of the requests? This requires the idea of ​​"locking", and how to lock it will be introduced below.

Transactions in Redis

Three features of Redis transactions

  • Separate isolation operation: All commands in the transaction will be serialized and executed in order. During the execution of the transaction, it will not be interrupted by the command request sent by other clients.
  • There is no concept of isolation level: the commands in the queue will not be actually executed before they are submitted, because any instructions will not be actually executed before the transaction is submitted, so there is no "query within the transaction to see the update in the transaction" , Query can’t be seen outside the transaction" this is an extremely headache problem.
  • Atomicity is not guaranteed: If a command fails to execute in the same transaction in redis, the subsequent commands will still be executed without rollback.

In Redis, the three commands Multi, Exec, and Discard are used to manipulate transactions.

Multi command

The Multi command is the beginning of the transaction, and the data operation commands after this command will be added to the queue to be executed instead of being executed directly.

127.0.0.1:6379> multi
OK
127.0.0.1:6379> set myName mingbo
QUEUED
127.0.0.1:6379> get myName
QUEUED

After the multi command, the set command is not executed immediately, but the status in the QUEUED queue.

Exec command

After all the transaction commands are added, use the Exec command to execute all the commands in the queue. Connect:

127.0.0.1:6379> exec
1) OK
2) "mingbo"

At this time, the commands in the transaction will be executed in order. It should be noted that, unlike common relational database transactions, in Redis transactions, if there is a command that fails to execute, the transaction will not stop there, but will continue to execute.

127.0.0.1:6379> multi
OK
127.0.0.1:6379> set myName mingbo
QUEUED
127.0.0.1:6379> get myName
QUEUED
127.0.0.1:6379> discard
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379> set myName mingbo
QUEUED
127.0.0.1:6379> incr myName   //myName不是数字类型,incr命令会执行失败
QUEUED
127.0.0.1:6379> get myName
QUEUED
127.0.0.1:6379> exec
1) OK
2) (error) ERR value is not an integer or out of range
3) "mingbo"

Except for errors reported during execution, if the commands in the queue have direct syntax errors, the command queue in the transaction cannot be executed using the exec command. After all, it is a serious "compiled error".

Discard command

If you use the Multi command to start the transaction, you can use the Discard command to cancel the transaction before the Exec command executes the transaction.

127.0.0.1:6379> multi
OK
127.0.0.1:6379> set myName mingbo
QUEUED
127.0.0.1:6379> get myName
QUEUED
127.0.0.1:6379> discard
OK

Locks in Redis

In order to control the unreasonable data caused by operating the same piece of data at the same time in concurrency, we have defined the idea of ​​"lock". Here is a brief introduction to two common lock ideas: pessimistic lock and optimistic lock.

Pessimistic lock

Pessimistic lock (Pessimistic Lock), its idea is to lock when reading the data to be operated, so that when other transactions get the data again, they will find that there is a lock and cannot be read, and data operations cannot be performed. Only when the lock is unlocked after the previous transaction is completed, the data can be operated by the next transaction.

It is called pessimistic lock because it is a concurrency control method with a pessimistic attitude towards data modification. We generally believe that the probability of data being modified concurrently is relatively large, so it is necessary to lock it before modification.

Advantages: to ensure the security of data concurrency control. Disadvantages: reduced parallelism, only one transaction can be processed at the same time, and other transactions need to be queued.

Optimistic lock

Optimistic Lock (Optimistic Lock), the idea is to optimistically believe that the data fetched will not be operated by others at the same time, so it will not be locked when reading. But before submitting the manipulated data, it will be judged whether anyone else has manipulated the data during the operation. Generally, the version number and other mechanisms are used to judge.

Advantages: Improved throughput, data can be read at the same time; Disadvantages: increased transaction execution failure rate.

Redis uses this check-and-set optimistic locking mechanism to achieve transactional lock control.

Watch and Unwatch commands

The Watch command is used to monitor the key. If this (or these) keys are changed by other commands before the transaction is executed, the transaction will be interrupted.

The case of cooperating with Redis transaction is as follows: First, in two clients, watch myAge separately, and add transaction operations:

127.0.0.1:6379> watch myAge
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379> incr myAge
QUEUED

At this point, exec executes the transaction in a client. In the client that executes first, the data will be successfully modified:

127.0.0.1:6379> exec
1) (integer) 1

But cutting off another client to execute the transaction, because it is executed after the data has been modified, it will fail:

127.0.0.1:6379> exec
(nil)