Related commands: DISCARD EXEC MULTI unwatch WATCH transaction
Multi,exec,discard and watch are the basis of Redis transactions. They allow a set of commands to be executed in one step, with two important guarantees: All commands in the transaction are serialized and executed sequentially. In the process of performing a redis transaction, there is no case that a request by another client is being serviced. This ensures that the command is executed as a separate isolated operation. Redis transactions are atomic, whether all commands are handled or no commands are processed. The EXEC command triggers execution of all the commands in the transaction, so if the client loses its connection to the server in the context of the transaction before invoking the Multi command, no action is taken, and all operations are performed if the EXEC command is called. When using append-only files, Redis ensures that transactions are written to disk using a single write (2) system call. However, if the Redis server crashes or is killed by a system administrator in some way, only some of the operations may be registered. Redis detects this when it restarts and exits when an error occurs. Use the Redis-check-aof tool to remove partial transactions to fix only the append files so that the server can be restarted.
Starting with version 2.2, Redis allows for additional guarantees for both of these, using optimistic locking patterns that are very similar to Check-and-set (CAS) operations. This will be recorded later on this page. usage
Use the Multi command to enter the Redis transaction. The command always responds with OK. At this point the user can issue multiple commands. Redis does not execute these commands, but instead queues them. After exec is called, all commands are executed.
Calls discard instead of flushing the transaction queue and exits the transaction.
The following example atomically increments key foo and bar.
> MULTI
Ok
> INCR foo
QUEUED
> INCR Bar
QUEUED
> EXEC
1) (integer) 1
2) (integer) 1
As can be seen from the previous session, EXEC returns an array of responses, each of which is the response of a single command in the transaction, in the same order as the command was issued.
When the Redis connection is in the context of the multi request, all commands are replied with a string of queued (sent from the perspective of the Redis protocol as a status reply). When exec is called, the queued commands are simply scheduled to execute. errors in the transaction
During a transaction, you may encounter two command errors: The command may not be queued, so an error may occur before calling exec. For example, the command may be syntactically incorrect (wrong number of arguments, wrong command name ...). ), or there may be some critical conditions, such as a low memory condition (if the server is configured to use maxmemory indication). For example, because we perform an action on a key with an error value (for example, by invoking a list operation on a string value), the command may fail after calling exec.
By examining the return value of the queued command, the client is used to detect the first error that occurred before the EXEC call: If the command responds with queued, it is queued correctly, or Redis returns an error. If an error occurs while queuing a command, most clients abort the transaction and discard it.
However, starting with Redis 2.6.5, the server remembers an error during the cumulative command and refuses to perform a transaction that returns an error during exec and automatically discards the transaction.
Prior to Redis 2.6.5, the behavior was to perform transactions only within a subset of the commands that were successfully queued in case the client called EXEC regardless of previous errors. The new behavior makes it easier to mix transactions with pipelining, so the entire transaction can be sent one at a time, and all replies are read at once.
Errors that occur after exec are not handled in a special way: even if some commands fail in a transaction, all other commands are executed.
This is more clear at the protocol level. In the following example, even if the syntax is correct, a command fails when it executes:
Trying 127.0.0.1 ...
Connected to localhost.
Escape character is ' ^] '.
MULTI
+ok
SET a 3
Abc
+queued
Lpop A
+queued
Exec
* *
+ok
-err operation against a key holding the wrong kind of value
EXEC returns two-element Bulk string reply, one of which is the OK code and the other is the-err reply. The client library needs to find a sensible way to make the error available to the user.
It is important to note that even if the command fails, all other commands in the queue will be processed –redis will not stop processing the command.
Another example, using the wire protocol again using the Telnet protocol, can show how the syntax error is reported:
MULTI
+ok
INCR a b C
-err wrong number of arguments for ' incr ' command
This time because of a syntax error, the wrong INCR command is not queued at all. Why Redis does not support rollback.
If you have a relational database background, Redis commands may fail during transaction processing, but Redis will perform the rest of the transaction instead of rolling back the transaction, which may seem strange to you.
However, there are good ideas for this behavior: If you invoke the Redis command using the wrong syntax (and you cannot detect a problem during command queuing), or for a key that holds the wrong data type, the Redis command may fail: This means that the failed command is actually the result of a programming error, and an error that is likely to be detected during the development process, rather than in production. Redis is simplified internally and is faster because it does not require rollback functionality.
One point of view against the Redis point of view is that the error has occurred, but it should be noted that in general, rollback does not prevent programming errors. For example, if the query increases the key by 2 instead of 1, or adds the wrong key, the rollback mechanism cannot provide help. Since no one can save the programmer's error, and the type of error required for the Redis command to fail is unlikely to enter the production environment, we have chosen a simpler and quicker way to not support error rollback. Discard Command Queue
Discard can be used to abort a transaction. In this case, no commands are executed and the connection status is restored to normal.
> SET foo 1
Ok
> MULTI
Ok
> INCR foo
QUEUED
> DISCARD
Ok
> GET foo
"1" optimistic locking using Check-and-set
Watch is used to provide check-and-set (CAS) behavior for redis transactions.
Monitoring keys are monitored to detect changes to them. If at least one monitored key has been modified before the EXEC command, the entire transaction is aborted, and EXEC returns a null reply to notify the transaction of failure.
For example, suppose we need to automatically increment the value of key by 1 (let's assume that Redis has no incr).
The first attempt may be as follows:
val = GET MyKey
val = val + 1
SET MyKey $val
This works reliably only when we have a client that performs operations within a given time. If multiple clients try to increment key at approximately the same time, a race condition occurs. For example, clients A and B will read the old values, for example 10, the values of the two clients will be incremented to 11, and the set will be the value of the key. So the final value will be 11 instead of 12.
Thanks to watch, we are able to simulate this problem well:
WATCH MyKey
val = GET MyKey
val = val + 1
MULTI
SET MyKey $val
Exec
Using the code above, if there is a race condition and another client modifies the result of Val within the time between our call to watch and our call to exec, the transaction will fail.
We just need to repeat this operation and hope we won't get a new competition this time. This form of locking, called optimistic locking, is a very powerful form of locking. In many use cases, multiple clients will access different keys, so collisions are not likely to occur-typically, this action is not required. Watch Description
So watch really is what. This is a command that makes EXEC conditional: only if no watched key has been modified will we require Redis to execute the transaction. (But they may be changed by the same client in the transaction without aborting it, more of this) otherwise, the transaction will not enter at all. (Note that if you watch volatile key and Redis expires the key after you watch the key, Exec will continue to work.) It's more of this. )
Watch can be called multiple times. Simply put, all watch calls will have the effect of watch changing from the start of the call until exec is called. You can also send any number of keys to a single watch call.
When exec is called, all keys are unwatched, regardless of whether the transaction is aborted. In addition, when the client connection is closed, all will be unwatched.
You can also use the Unwatch command (no parameters) to refresh all watch keys.
Sometimes, we are optimistic about locking a few keys, which is useful, because we may need to execute a transaction to change these keys, but we do not want to continue after reading the current contents of key. When this happens, we only need to call unwatch so that the connection is free for the new transaction. using watch to achieve Zpop
Give a good example of how watch is used to create a new atomic operation, or Redis does not support implementing Zpop, which is an atomic command to eject an element from a sorted collection in a lower fraction. This is the simplest implementation:
WATCH Zset
element = Zrange Zset 0 0
MULTI
Zrem zset Element
Exec
If exec fails (that is, returns an empty reply), we only need to repeat the operation. Redis Scripts and Transactions
By definition, Redis scripts are transactional, so all the operations that you can perform with Redis transactions can be scripted, and often scripts will be simpler and quicker.
This repetition is due to the introduction of scripts in Redis 2.6, and the transactions already exist. However, it is not possible to remove support for transactions in a short time, because even if you do not use Redis scripting, you can still avoid a competitive situation, especially since the implementation of REDIS transactions is minimal, which is semantically appropriate.
However, in the near future, we will see that the entire user base is simply using scripts, which is not impossible. If this happens, we may discard and eventually delete the transaction.