当前位置:网站首页>[redis realizes seckill business ③] specific implementation of optimistic lock for oversold problem

[redis realizes seckill business ③] specific implementation of optimistic lock for oversold problem

2022-06-25 00:45:00 Bulst

Version number method

There are also two common ways to implement the version number mechanism :

  1. Use data version (Version) Record mechanism implementation , This is the most common implementation of optimistic locking . What is a data version ? Add a version identity to the data , This is generally done by adding a number type to a database table “version” Field to implement . When the data is read , take version The values of the fields are read together , The data is updated every time , Regarding this version Add the values of a .
    When we submit the update , Judge the records corresponding to the database table The current version information of is the same as that of the first time version Value comparison , If the current version number of the database table is fetched for the first time version The values are equal , Is updated , Otherwise, it is considered to be outdated data .
    If the update operations are executed in sequence , The version of the data (version) In turn, increasing , There is no conflict . However, if there are different business operations to repair the same version of data Change , that , The first submitted operation will send the data version Updated to 2, When A stay B The data is found when the update is submitted later version It has been modified , that A The update operation will fail .

  2. Use time stamps (timestamp). This implementation is similar to the first one , Also in need of optimistic lock control table Add a field to , Name doesn't matter , Field types use timestamps (timestamp), And the above version similar , Also check the timestamp of the data in the current database when the update is submitted and compare it with the timestamp obtained before the update , If consistent OK, Otherwise it's a version conflict .

 Insert picture description here

CAS Algorithm

CAS namely Compare And Swap( Comparison and exchange ), It's a well-known unlocked algorithm . No lock programming , That is, to achieve variable synchronization between multiple threads without using locks , In other words, the synchronization of variables can be realized without thread blocking , So it's also called nonblocking synchronization (Non-blocking Synchronization).

CAS An operation contains three operands —— Value of memory location (V)、 The original value of the expected (A) And the new value (B). perform CAS During operation , Compare the value of the memory location with the expected original value , If they match , The processor will automatically update the location value to the new value , otherwise , The processor does nothing .

Through optimistic lock + The way you spin , Solve the thread safety problem of data update , And the lock granularity is lower than that of mutex , Good concurrency performance .

Cycle to achieve :

public void addCount(String goodsId, Integer count) {
    
    while(true) {
    
        Goods goods = dao.selectByGoodsId(goodsId);
        if (goods == null) {
    
            throw new Execption(" The data doesn't exist ");
        }
        int count = goods.getCount() + count;
        goods.setCount(count);
        int count = dao.updateCount(goods);
        if (count > 0) {
    
            return;
        }   
    }
}

Recursive implementation :

public void addCount(String goodsId, Integer count) {
    
     Goods goods = dao.selectByGoodsId(goodsId);
        if (goods == null) {
    
            throw new Execption(" The data doesn't exist ");
        }
        int count = goods.getCount() + count;
        goods.setCount(count);
        int count = dao.updateCount(goods);
         if (count == 0) {
    
        addCount(goodsId, count)
    }
}

CAS Disadvantages of the algorithm

【1】 The cycle time is long and the cost is high : The spin CAS If it doesn't work for a long time , Will give CPU It's very expensive to execute .
【2】 Only one atomic operation of shared variables can be guaranteed : Only one atomic operation of shared variables can be guaranteed . When operating on a shared variable , We can use cycles CAS The way to guarantee atomic operation , But when operating on multiple shared variables , loop CAS There is no guarantee of atomicity of operation , You can use the lock at this time , Or there's a clever way , It is to combine multiple shared variables into a shared variable to operate . For example, there are two shared variables i=2,j=a, Merge ij=2a, And then use CAS To operate ij. from Java1.5 Start JDK Provides AtomicReference Class to ensure atomicity between reference objects , You can put multiple variables in one object CAS operation .
【3】ABA problem : because CAS It is necessary to check whether there is any change in the lower value when operating the value , Update if nothing changes , But if a value turns out to be A, Turned into B, It's changed again. A, So use CAS Check that its value has not changed , But it actually changed .ABA The solution to the problem is to use version number . Append the version number to the variable , Add the version number to each variable update 1, that A-B-A Will become 1A-2B-3A.

The illustration

 Insert picture description here

Code implementation

We can do this in the following way , If the quantity is equal to the quantity you find , Just buy

  //  If the quantity is equal to the quantity you find , Just buy 
  boolean updateBoolean = this.update().setSql("count = count - 1")
          .eq("id", id).eq("count", fruits.getId()).update();
  
  if (!updateBoolean) {
    
      return ResponseEntity.status(400).body(" The fruit is sold out , Come again next time !");
  }

But this will make it impossible for other users who should be able to buy , So the changes are as follows

        //  If the quantity is equal to the quantity you find , Just buy 
// boolean updateBoolean = this.update().setSql("count = count - 1")
// .eq("id", id).eq("count", fruits.getId()).update();
		//  If the remaining quantity is greater than 0, You can buy 
        boolean updateBoolean = this.update().setSql("count = count - 1")
                .eq("id", id).gt("count", 0).update();
        if (!updateBoolean) {
    
            return ResponseEntity.status(400).body(" The fruit is sold out , Come again next time !");
        }
原网站

版权声明
本文为[Bulst]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/176/202206242001480510.html