This is the 17th day of my participation in the Gwen Challenge
A, the transaction
Redis transactions are a combination of commands using multi-exec, which provides two important guarantees:
-
A transaction is an isolated operation. The methods in the transaction are serialized by Redis and executed sequentially. The transaction will not be interrupted by commands from other clients during execution.
-
A transaction is an atomic operation that either executes at all or does not.
Using transactions in Redis goes through three steps:
- Open the transaction
- Command queue
- Perform transactions
The command | instructions | note |
---|---|---|
multi | If a transaction command is enabled, subsequent commands are queued instead of being executed immediately | During the lifetime of a transaction, all Redis commands about data structures are enqueued |
watch key1 [key2….] | Listen for certain keys, and when the monitored key is modified before the transaction is executed, the transaction is rolled back | Use optimistic Locks |
unwatch key1 [key2….] | Unlisten for certain keys | – |
exec | Executes a transaction if the monitored key has not been modified, or rollback the command otherwise | Before executing a transaction queue store command, Redis checks whether the monitored key/value pair has changed, executes the command if it has not, and rolls back the transaction otherwise |
discard | Roll back the transaction | The transaction command that is queued is rolled back, after which it cannot commit with the exec command |
In spring scenarios where you want to use the same connection to operate the Redis command, you can use the Spring-provided SessionCallback interface.
package com.codeliu.transaction; import java.util.List; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import org.springframework.data.redis.core.RedisOperations; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.SessionCallback; @author liu */ public class TestTransaction {@suppressWarnings ({"resource", "rawtypes", "unchecked" }) @Test public void testTransaction() { ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml"); RedisTemplate rt = (RedisTemplate)applicationContext.getBean("redisTemplate"); @SuppressWarnings("unused") SessionCallback callBack = (SessionCallback)(RedisOperations ops)->{ ops.multi(); ops.boundValueOps("key1").set("value1"); Value = (String)ops.boundValueOps("key1").get(); System.out.println(value); List<String> list = ops.exec(); for(String l:list) { System.out.println(l); Value = (String)ops.boundValueOps("key1").get(); return value; }; // execute the redis command String value = (String)rt.execute(callBack); System.out.println(value); }}Copy the code
(1) Redis transaction rollback
Look at the picture below
Key1 = value1; key2 = null; key1 = value1; key2 = null;
Look at the picture below
You can see that we are using the wrong command format, Redis can immediately detect, before and after the command will not be executed, indicating that the transaction is rolled back.
(2) Use the watch command to monitor transactions
Redis references the CAS (compare and exchange) used in multithreading. The CAS principle can cause ABA problems
The table above shows ABA problems.
It is not enough to just record an old value for comparison, and there are other ways to avoid ABA problems. A common practice is to add a version field, incrementing version by 1 with each operation so that version can tell if the field has been changed.
In the process of executing transactions, Redis will not block the concurrency of other connections, but only ensures the consistency of data by comparing the key-value pairs monitored by Watch. Therefore, multiple Redis transactions can be executed concurrently in a non-blocking multi-threaded environment, and Redis transactions will not cause ABA problems.
moment | The client 1 | Client 2 | instructions |
---|---|---|---|
T1 | set key value1 | Client 1: Returns OK | |
T2 | watch key1 | Client 1: monitors KEY1 | |
T3 | multi | Client 1: Starts a transaction | |
T4 | set key2 value2 | Client 1: The transaction command is entered | |
T5 | – | set key1 val1 | Client 2: Change the value of key1 |
T6 | exec | – | Client 1: performs the transaction and checks to see if key1 monitored at T2 has been modified, because it has been modified, the transaction is rolled back. In fact, if client 2 executes set key Value1, it is also considered modified and returns nil, so there is no ABA problem |