Using MULTI and EXEC, we can place multiple commands into a transaction to ensure that either all or none of the commands in the transaction are executed to prevent data errors. However, sometimes only transactions cannot ensure the correctness of data, so Optimistic Locking provided by Redis is needed.
The command
-
WATCH key [key …] If the monitored key has been preemptively modified by another client before the transaction commits (i.e., before the EXEC command executes), the server will reject the client-committed transaction and return nil as a response to the transaction
127.0.0.1:6379> watch msg OK 127.0.0.1:6379> multi OK 127.0.0.1:6379> set msg haha QUEUED 127.0.0.1:6379> exec (nil) Copy the code
Executed before last transaction commits:
127.0.0.1:6379> multi OK 127.0.0.1:6379> set msg hehe QUEUED 127.0.0.1:6379> exec 1) OK Copy the code
Results:
127.0.0.1:6379 > get MSG "hehe"Copy the code
-
UNWATCH Unmonitors all keys
-
DISCARD abandons transaction execution and unmonitors all keys (equivalent to UNWATCH)
The difference between optimistic and pessimistic locks
- Optimistic locking monitors the locked data and allows multiple clients to attempt to modify the data at the same time, with the first client succeeding and the later client failing
- Pessimistic locking allows only one client to make changes to the data, while other clients need to wait for the client that is making the changes to complete before attempting to obtain the right to make changes
- For Redis, which does a lot of reading and writing, optimistic locking prevents the client from blocking: when a client fails to modify data, it simply retries without any waiting
Pitfalls of transaction and optimistic locking
- For a transaction, it is often necessary to think carefully about which keys should be locked: locking keys that should not be locked increases the chance of transaction failure, and may even cause errors in the program; If you forget to lock the key that should be locked, the program will create a race condition
- Sometimes to prevent race conditions, even though the operation itself does not need a transaction, the command is wrapped in a transaction for optimistic locking to take effect, which increases implementation complexity and incurs additional performance costs