Redis05: transaction processing practice

Redis transaction introduction

summary

Redis adopts the optimistic locking method for transaction control. It uses the watch command to see the given key. When exec(t commits the transaction), if the monitored key is valid for the whole connection, such as disconnecting the connection, the supervisor and transaction will be automatically cleared. Of course, the exec, discard and unwatch commands will clear all monitoring in the connection

Basic instruction

multi open transaction

exec commit transaction

discard cancel transaction

watch monitoring. If the monitored value changes, the transaction submission will fail

unwatch cancel monitoring

Redis ensures that all commands in a transaction are executed or not executed (atomicity). If the client is disconnected before sending the EXEC command, redis will empty the transaction queue and all commands in the transaction will not be executed. Once the client sends the EXEC command, all commands will be executed. Even if the client is disconnected, it doesn't matter, because all commands to be executed have been recorded in redis.

Redis transaction control practice

exec commit transaction

Simulated transfer, tony 500, jack 200, tony to Jack 100.

127.0.0.1:6379> set tony 500
OK
127.0.0.1:6379> set jack 200
OK
127.0.0.1:6379> mget tony jack
1) "500"
2) "200"
127.0.0.1:6379> multi #Open transaction
OK
127.0.0.1:6379(TX)> decrby tony 100 #All instruction operations are queued
QUEUED
127.0.0.1:6379(TX)> incrby jack 100
QUEUED
127.0.0.1:6379(TX)> mget tony jack
QUEUED 
127.0.0.1:6379(TX)> exec  #Commit transaction
1) (integer) 400
2) (integer) 300
3) 1) "400"
   2) "300"
127.0.0.1:6379> mget tony jack
1) "400"
2) "300"
127.0.0.1:6379>

discard cancel transaction

Note that the redis transaction is too simple. Instead of rolling back, it has to be cancelled.

127.0.0.1:6379> mget tony jack
1) "400"
2) "300"
127.0.0.1:6379> multi
OK
127.0.0.1:6379> incrby jack 100
QUEUED
127.0.0.1:6379> discard
OK
127.0.0.1:6379> get jack
"300"
127.0.0.1:6379> exec
(error) ERR EXEC without MULTI

When an incorrect instruction occurs, the transaction will also be cancelled automatically.

127.0.0.1:6379> mget tony jack
1) "400"
2) "300"
127.0.0.1:6379> multi
OK
127.0.0.1:6379(TX)> incrby jack 100
QUEUED
127.0.0.1:6379(TX)> abcd
(error) ERR unknown command `abcd`, with args beginning with:
127.0.0.1:6379(TX)> get jack
QUEUED
127.0.0.1:6379(TX)> exec
(error) EXECABORT Transaction discarded because of previous errors.
127.0.0.1:6379> get jack
"300"
127.0.0.1:6379>

Second kill ticket grabbing transaction

Based on a second kill and rush purchase case, demonstrate the optimistic lock mode of redis, for example

Step 1: open client 1 and perform the following operations

127.0.0.1:6379> set ticket 1
OK
127.0.0.1:6379> set money 0
OK
127.0.0.1:6379> watch ticket		#Optimistic lock. Observe the value. If the value changes, the transaction fails
OK
127.0.0.1:6379> multi				#Open transaction
OK
127.0.0.1:6379> decr ticket
QUEUED
127.0.0.1:6379> incrby money 100
QUEUED

Step 2: open client 2 and perform the following operations. Before client 1 submits the transaction, client 2 buys the ticket

127.0.0.1:6379> get ticket
"1"
127.0.0.1:6379> decr ticket
(integer) 0

Step 3: return to client 1: commit the transaction and check the value of ticket

127.0.0.1:6379> exec
(nil) #Execute transaction, failed
127.0.0.1:6379> get ticket
"0"
127.0.0.1:6379> unwatch #Cancel monitoring

Jedis client transaction operations

Conduct transaction test based on Jedis, and the code is as follows:

package com.jt;
import org.junit.Test;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.Transaction;

public class JedisTransactionTests {

    @Test
    public void testTransaction(){
        Jedis jedis=new Jedis("192.168.126.130",6379);
        jedis.auth("123456");
        jedis.set("tony","300");
        jedis.set("jack","500");
        //To implement the operation, tony transfers 100 to jack
        //Open transaction
        Transaction multi = jedis.multi();
        //Perform business operations
        try {
            multi.decrBy("tony", 100);
            multi.incrBy("jack", 100);
            int n=100/0;//Simulation anomaly
            //Commit transaction
            multi.exec();
        }catch(Exception e) {
            //An exception occurred to cancel the transaction
            multi.discard();
        }
        String tonyMoney=jedis.get("tony");
        String jackMoney=jedis.get("jack");
        System.out.println("tonyMoney="+tonyMoney);
        System.out.println("jackMoney="+jackMoney);
        jedis.close();
    }
}

Jedis client second kill operation practice

package com.jt.demos;

import redis.clients.jedis.Jedis;
import redis.clients.jedis.Response;
import redis.clients.jedis.Transaction;

import java.util.List;

/**
 * redis Second kill exercise:
 * Simulate that both threads rush to buy the same ticket (consider music lock)
 */
public class SecondKillDemo02 {

      public static void secKill(){
          Jedis jedis=new Jedis("192.168.126.130",6379);
          jedis.auth("123456");
          jedis.watch("ticket","money");
          String ticket = jedis.get("ticket");
          if(ticket==null||Integer.valueOf(ticket)==0)
              throw new RuntimeException("No inventory");
          Transaction multi = jedis.multi();
          try {
              multi.decr("ticket");
              multi.incrBy("money", 100);
              List<Object> exec = multi.exec();
              System.out.println(exec);
          }catch (Exception e){
              e.printStackTrace();
              multi.discard();
          }finally {
              jedis.unwatch();
              jedis.close();
          }
      }
      public static void main(String[] args) {
          Jedis jedis=new Jedis("192.168.126.130",6379);
          jedis.auth("123456");
          jedis.set("ticket","1");
          jedis.set("money","0");

          Thread t1=new Thread(()->{
              secKill();
          });
          Thread t2=new Thread(()->{
              secKill();
          });
          t1.start();
          t2.start();
      }
}

Keywords: Database Redis

Added by Poomerio on Tue, 12 Oct 2021 03:52:38 +0300