Redis transaction and optimistic lock

preface

  • affair

① atomicity. A transaction is an inseparable work unit, and the operations included in the transaction are either done or not done.
② Consistency. Transactions must change the database from one consistency state to another. Consistency and atomicity are closely related.
③ isolation. The execution of a transaction cannot be interfered by other transactions. That is, the operations and data used within a transaction are isolated from other concurrent transactions, and the concurrent transactions cannot interfere with each other.
④ durability. Persistence, also known as permanence, means that once a transaction is committed, its changes to the data in the database should be permanent. The following other operations or faults should not have any impact on it.
There is no concept of isolation level in Redis transactions!
In Redis, a single command guarantees atomicity, but transactions do not guarantee atomicity!

  • Optimistic lock

① When concurrency may occur in the program, it is necessary to ensure the accuracy of the data in the case of concurrency, so as to ensure that when the current user operates with other users, the result is the same as that when he operates alone.
② If concurrency control is not done well, dirty reading, unreal reading and non repeatable reading may be caused.
Optimistic locking can be realized in Redis!

1, How does Redis implement transactions?

① Normal execution of transactions

127.0.0.1:6379> multi  #Open transaction
OK
127.0.0.1:6379> set name dingyongjun  #Add data
QUEUED
127.0.0.1:6379> set age 26  #Add data
QUEUED
127.0.0.1:6379> set high 172  #Add data
QUEUED
127.0.0.1:6379> exec  Execute transactions
1) OK
2) OK
3) OK
127.0.0.1:6379> get name  #Successful data acquisition proves successful transaction execution
"dingyongjun"
127.0.0.1:6379> get age
"26"

② Abandon transaction

127.0.0.1:6379> multi  #Open transaction
OK
127.0.0.1:6379> set name dingyongjun  #Add data
QUEUED
127.0.0.1:6379> set age 26  #Add data
QUEUED
127.0.0.1:6379> discard  #Abandon transaction
OK
127.0.0.1:6379> get name  #Will not perform the add operation in the transaction
(nil)

③ Compile time exceptions, code problems, or command problems, all commands will not be executed

127.0.0.1:6379> multi  #Open transaction
OK
127.0.0.1:6379> set name dingyongjun  #Add data
QUEUED
127.0.0.1:6379> set age 23  #Add data
QUEUED
127.0.0.1:6379> getset name  #Enter an incorrect command, and an error has been reported at this time, but this is still in the transaction queue
(error) ERR wrong number of arguments for 'getset' command
127.0.0.1:6379> set high 173  #Add data
QUEUED
127.0.0.1:6379> exec  #Execute transactions, report errors, and all commands will not be executed
(error) EXECABORT Transaction discarded because of previous errors.
127.0.0.1:6379> get name  #The obtained data is empty, which proves that it has not been implemented
(nil)

④ For runtime exceptions, except that syntax errors will not be executed and exceptions are thrown, other correct commands can be executed normally

127.0.0.1:6379> multi  #Open transaction
OK
127.0.0.1:6379> set name dingyongjun  #Add string data
QUEUED
127.0.0.1:6379> incr name  #Self incrementing string data
QUEUED
127.0.0.1:6379> set age 23  #Add data
QUEUED
127.0.0.1:6379> get age  #get data
QUEUED 
127.0.0.1:6379> exec  #Execute transactions. Although an error is reported in the auto increment operation of string data, other commands can be executed normally
1) OK
2) (error) ERR value is not an integer or out of range
3) OK
4) "23"
127.0.0.1:6379> get age  #Data acquisition succeeded
"23"

⑤ Summary: it can be concluded from the above that Redis supports single command transactions, but transactions cannot guarantee atomicity!

2, How does Redis implement optimistic lock?

① watch

127.0.0.1:6379> set money 100  #Add money 100
OK
127.0.0.1:6379> set cost 0  #Add expense 0
OK
127.0.0.1:6379> watch money  #Monitor money
OK
127.0.0.1:6379> multi  #Open transaction
OK
127.0.0.1:6379> DECRBY money 30  #Money -30
QUEUED
127.0.0.1:6379> incrby cost 30  #Cost +30
QUEUED
127.0.0.1:6379> exec  #Execute transaction, successful! Only when there is no change in the data can we succeed
1) (integer) 70
2) (integer) 30

② Multithreaded test watch
#Thread 1

#Thread 1
127.0.0.1:6379> set money 100  #Add money 100
OK
127.0.0.1:6379> set cost 0  #Add expense 0
OK
127.0.0.1:6379> watch money  #Turn on monitoring (Le Guan lock)
OK 
127.0.0.1:6379> multi  #Open transaction
OK
127.0.0.1:6379> DECRBY money 20  #Money -20
QUEUED
127.0.0.1:6379> INCRBY cost 20   #Cost +20
QUEUED
#Don't execute it here. Execute thread 2 first to modify the monitored value
127.0.0.1:6379> exec  #An error is reported during execution, because we have monitored the value of money. If the transaction wants to operate on this value
#The monitor will judge whether this value is normal. If it changes, the transaction execution fails!
(nil)

#Thread 2

#Thread 2, this operation is executed before the transaction is executed
127.0.0.1:6379> INCRBY money 20  #Money +20
(integer) 120

③ Summary: the difference between optimistic lock and pessimistic lock.
Pessimistic lock: there will be problems at any time, so I have been monitoring. Before the current step is completed, no thread is allowed to execute, which is a waste of performance! Generally not used!
Optimistic lock: only when updating the data, judge whether someone has modified the monitored data during this period. If not, the transaction will be executed normally, otherwise the execution will fail!

Tags: Redis

Posted by safra on Fri, 29 Jul 2022 02:34:27 +0930