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