当前位置:网站首页>Redis transaction

Redis transaction

2022-07-19 08:05:00 Program three two lines

One 、 summary

redis A transaction is a separate isolation operation , All commands in the transaction are serialized 、 Execute in order . The transaction execution process will not be interrupted by the command requests sent by other clients , The main function of transactions is to concatenate multiple commands to prevent other commands from jumping in the queue

Two 、 Transaction execution command

redis and mysql Transactions are fundamentally different ,redis From input Multi Command start , All the entered commands will enter the command queue in turn , But will not execute , Until the execution process is entered Exec after ,redis The previous commands in the command queue will be executed successively , In the process of team formation, you can go through discard Give up team , As shown in the following figure

Demonstrate alignment

Demonstrate giving up teaming

 

3、 ... and 、 Transaction exception error

First error : An error occurred in a command during the formation stage , The entire queue will be canceled during execution

The second mistake : An error occurred in a column in the queue during execution , Only those with errors will not be executed , No rollback , Other normal execution

Four 、 Transaction conflict and handling

1、 Overview of transaction conflicts

immediately 618 了 、 Suppose a scene : Many people have your account and only 10000, At the same time 618 Rush purchase , Three requests were sent at the same time

A request wants to reduce the amount 8000

A request wants to reduce the amount 5000

A request wants to reduce the amount 1000

These three requests are sent at the same time , If the implementation is successful , Then the balance of the account becomes 10000-8000-5000-1000 = -4000, At this time, the account balance becomes negative , Obviously, this is very unreasonable in real life .

At this time, all we can think of is locking .

2、 Resolve transaction conflicts

2.1、 Pessimistic locking

seeing the name of a thing one thinks of its function , It's a very pessimistic kind , Like wishful thinking. Every time I go to get the data, I always think that others will change , So every time I get the data, I lock it , So that if people want to take this data, they will block Until it gets the lock . There are many lock mechanisms used in traditional relational databases , For example, line locks. , Table lock, etc. , Read the lock , Write locks, etc. , It's all locked before the operation .

2. 2、 Optimism lock

And pessimistic lock lock-in will not lock when getting data , Because he believes that the world is beautiful , No one else will modify , But out of rigor, I will check whether it has been modified at the moment of changing the data . You can use mechanisms like version numbers . Optimistic lock is suitable for multi read applications , This can improve throughput .Redis It's using this check-and-set The mechanism implements the .

Optimistic lock is more efficient than pessimistic lock , Because the pessimistic lock will be locked every time, while the optimistic lock just checks whether the version number is the version number just obtained when modifying the data, so it cannot be implemented , It's about execution .

3、redis in WATCH

In execution multi Before , Execute first watch key1 [key2], You can watch one ( Or more ) key , If before the transaction is executed ( Or these ) key Altered by other orders , Then the business will be interrupted .

example :

Set a key to balance The value is 10 String type data .

Use watch monitor

Open two clients , Start the transaction pair after monitoring separately balance Conduct +100 operation , Once the client submits first, it will succeed , Client 2 submission will fail , This is it. WAYCH Monitor transactions , Prevent transaction conflicts .

Client 1 : Successful execution of transaction

Client 2 : Failed to execute transaction

summary

    Concurrency problems are easy to occur in practical applications 、 So we're going to be here redis Locking in transactions solves the conflict problem of transactions

    stay redis Used in check-and-set Optimistic locking mechanism realizes transaction

   redis Optimistic lock use in watch Command to achieve

4、redis Case of transaction locking mechanism --- seckill

4.1、 summary

A seckill mainly consists of two operations: reducing the number of goods and recording successful users

/**
     *  Whether the second kill is successful 
     * @param uid  Second kill users 
     * @param pid  goods id
     * @return  Seckill success 
     */
    public Boolean doKill(String uid,Integer pid){
        //1.uid pid Judge not empty 
        if(uid == null || pid == null){
            return false;
        }
        //2. Connect jedis
        Jedis jedis = new Jedis("127.0.0.1","6379");
        //3. Splicing key
        // stock key
        String kcKey = "kc"+pid;
        // user key
        String userKey = "user"+pid;

        //4. Judge whether the inventory is empty 
        String kc = jedis.get(kcKey;
        if(kc == null){
            jedis.close();
            return false;
        }
        //5. Judge whether the user repeats the second kill 
        if(jedis.sismember(userKey,uid)){
            jedis.close();
            return false;
        }
        //6. The stock is greater than 0
        if(Integer.parseInt(kc)<=0){
            jedis.close();
            return false;
        }
        //7. seckill 
        jedis.decr(kcKey);
        jedis.sadd(userKey,uid);// user id When the value of set Type of 
        jedis.close();
        return true;
    }

4.2、 Concurrency issues

Using tools ab Simulate concurrency or jmeter There are two problems when simulating the request

1、 Connection timeout ( A lot of requests redis Lead to blocking )

Solution : Lead into the connection pool , Customize a connection pool tool class as follows

import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;

public class JedisPoolUtils {
    private static volatile JedisPool jedisPool = null;

    private JedisPoolUtils(){

    }
// Lazy double check lock , Thread safety 
    public static JedisPool getJedisPoolInstance() {
        if(null == jedisPool) {
            synchronized (JedisPoolUtils.class) {
                if(null == jedisPool) {
                    JedisPoolConfig poolConfig = new JedisPoolConfig();
                    poolConfig.setMaxTotal(200);
                    poolConfig.setMaxIdle(32);
                    poolConfig.setMaxWaitMillis(100*1000);
                    poolConfig.setTestOnBorrow(true);
                    jedisPool = new JedisPool(poolConfig,"192.168.235.128",6379);
                }
            }
        }
        return jedisPool;
    }

    public static void release(JedisPool jedisPool, Jedis jedis) {
        if(null != jedis) {
            jedisPool.returnResourceObject(jedis);
        }
    }
}

The spike code above has been changed

Jedis jedis = new Jedis("127.0.0.1","6379");

change

2、 Concurrent error problem , Inventory becomes negative

Solve by optimistic lock , Change the above code to add monitoring and transactions

4.3、 Inventory remaining problems

The oversold problem can be solved through the above , But there will be inventory The remaining questions , Because optimistic locking is controlled by modifying this version , For example 10 After monitoring users, the version is changed to 1 The user versions changed later are inconsistent and will not be operated, so the remaining

resolvent , adopt lua Script solution

lua summary

lua It will be complex or multi-step redis The operation is written into a script , Submit to redis perform , Reduce repeated connections redis Times to improve performance ,lua Script similar redis Business , It has certain atomicity , Will not be interrupted by other orders , You can do some redis Transactional operations , however redis Of lua Script only in redis2.6 The above version can be used , utilize lua The script solves the oversold problem , It's actually using redis The single thread feature uses task queues to solve the problem of task concurrency

Implementation class

4.4、 Expand

For the second kill operation spring boot ,redis template It can also be realized

/**
 *  adopt redis  Business   Achieved seckill 
 * @param skuCode  Commodity code 
 * @param buyNum  Purchase quantity 
 * @return  Purchase quantity 
 */
@Service
public class GoodsServiceImpl {
 
	@Autowired
	StringRedisTemplate redisTemplate;
	//redis For any illegal value , All called ERR. use RedisTemplate  Serialized numbers cannot be converted 
	// Use GenericToStringSerializer、StringRedisSerializer Serializer , You can use increment Method    The number saved is   10  instead of "10"  character string 
	
/* 1 redisTemplate.excute(SessionCallback sessionCallback)  It's for the execution of affairs api
 * 2  So to achieve SessionCallback  To achieve redis  Business .
 * 3  If direct   adopt redisTemplate  Execute the transaction command   Will report a mistake */
	public Long flashSellByRedisWatch(String skuCode,int num){
		
		SessionCallback<Long> sessionCallback = new SessionCallback<Long>() {
 
			@SuppressWarnings("unchecked")
			@Override
			public Long execute(RedisOperations operations) throws DataAccessException {
				int result = num;
				//redis  Optimism lock 
				operations.watch(skuCode);
                ValueOperations<String, String> valueOperations = operations.opsForValue();
                String goodNumStr = valueOperations.get(skuCode);
                Integer goodNum = Integer.valueOf(goodNumStr);
                // Mark the beginning of a transaction block .
                // Multiple commands in a transaction block are put into a queue in sequence ,
                // Finally by  EXEC  Command atomicity (atomic) Carry out smoothly .
                operations.multi();
                if (goodNum>=num) {
					valueOperations.increment(skuCode, 0-num);// A negative number means you need to reduce the number of goods 
				}else{
					result = 0;
				}
                // The result set of multiple command execution 
                List exec = operations.exec();
                if(exec.size()>0){
                	System.out.println(" Successful implementation : "+exec);
                }
				return (long) result;
			}
		};
		return redisTemplate.execute(sessionCallback);
	}
}

原网站

版权声明
本文为[Program three two lines]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/200/202207170557240932.html