Summary and Practice of Mysql Optimistic Lock

Optimistic Lock Introduction:

Optimistic Locking is a relative pessimistic lock. Optimistic Locking assumes that data will not conflict in general. Therefore, when data is submitted and updated, it will formally detect the conflict of data. If conflict is found, it will let the user return the wrong information and let the user decide. What to do? So how can we achieve the optimistic lock? Generally speaking, there are two ways:

1. Using Version recording mechanism is the most common way to implement optimistic lock. What is data version? That is to say, adding a version identifier to the data is usually achieved by adding a numeric "version" field to the database table. When the data is read, the value of the version field is read out together, and the version value is added by one for each update of the data. When we submit an update, we judge that the current version information of the database table corresponding to the record is compared with the version value taken out for the first time. If the current version number of the database table is equal to the version value taken out for the first time, it will be updated, otherwise it will be considered as expired data. Use the following picture to illustrate:

As shown in the figure above, if the update operation is executed sequentially, the versions of the data are incremented sequentially without conflict. However, if there are different business operations to modify the same version of data, then the first submission operation (Figure B) will update the data version to 2. When A submits the update after B, it finds that the data version has been modified, then the update operation of A will fail.

 

2. The second way to achieve optimistic locking is similar to the first one. It also adds a field to the table that needs optimistic locking control. The name does not matter. The field type uses a timestamp, which is similar to the version above. It also checks the timestamp and itself of the data in the current database when updating the submission. The timestamps retrieved before the update are compared. If they are consistent, then OK, otherwise they are version conflicts.

 

Use examples: Take MySQL InnoDB as an example

Take the previous example as an example: there is a field status in the goods table of goods, status 1 represents that the goods have not been ordered, status 2 represents that the goods have been ordered, so we must ensure that the status of the goods is 1 when we place an order for a certain commodity. Suppose the id of the product is 1.

 

The next operation consists of three steps:

1. Query out commodity information

select (status,status,version) from t_goods where id=#{id}

2. Generating orders based on commodity information

3. Modify the commodity status to 2

update t_goods 

set status=2,version=version+1

where id=#{id} and version=#{version};

 

In order to use optimistic locks, we first modify the t_goods table and add a version field with a default version value of 1.

The initial data of the t_goods table are as follows:

  1. mysql> select * from t_goods;  
  2. +----+--------+------+---------+  
  3. | id | status | name | version |  
  4. +----+--------+------+---------+  
  5. |  1 |      1 | Prop |       1 |  
  6. |  2 |      2 | equipment |       2 |  
  7. +----+--------+------+---------+  
  8. rows in set  
  9.   
  10. mysql>  

For the implementation of optimistic lock, I use MyBatis to practice, as follows:

Goods entity class:

  1. /** 
  2.  * ClassName: Goods <br/> 
  3.  * Function: Commodity entities. <br/>
  4.  * date: 2013-5-8 09:16:19 <br/> in the morning
  5.  * @author chenzhou1025@126.com 
  6.  */  
  7. public class Goods implements Serializable {  
  8.   
  9.     /** 
  10.      * serialVersionUID:Serialized ID.
  11.      */  
  12.     private static final long serialVersionUID = 6803791908148880587L;  
  13.       
  14.     /** 
  15.      * id:Primary key id.
  16.      */  
  17.     private int id;  
  18.       
  19.     /** 
  20.      * status:Commodity status: 1 has not ordered, 2 has ordered.
  21.      */  
  22.     private int status;  
  23.       
  24.     /** 
  25.      * name:Commodity name.
  26.      */  
  27.     private String name;  
  28.       
  29.     /** 
  30.      * version:Commodity data version number.
  31.      */  
  32.     private int version;  
  33.       
  34.     @Override  
  35.     public String toString(){  
  36.         return "good id:"+id+",goods status:"+status+",goods name:"+name+",goods version:"+version;  
  37.     }  
  38.   
  39.     //setter and getter  
  40.   
  41. }  

GoodsDao

  1. /** 
  2.  * updateGoodsUseCAS:Use CAS(Compare and set) to update commodity information. <br/>.
  3.  * 
  4.  * @author chenzhou1025@126.com 
  5.  * @param goods Goods target
  6.  * @return Number of rows affected
  7.  */  
  8. int updateGoodsUseCAS(Goods goods);  

mapper.xml

  1. <update id="updateGoodsUseCAS" parameterType="Goods">  
  2.     <![CDATA[ 
  3.         update t_goods 
  4.         set status=#{status},name=#{name},version=version+1 
  5.         where id=#{id} and version=#{version} 
  6.     ]]>  
  7. </update>  

Goods DaoTest test test class

  1. @Test  
  2. public void goodsDaoTest(){  
  3.     int goodsId = 1;  
  4.     //According to the same id, the product information is queried and assigned to two objects.
  5.     Goods goods1 = this.goodsDao.getGoodsById(goodsId);  
  6.     Goods goods2 = this.goodsDao.getGoodsById(goodsId);  
  7.       
  8.     //Print current merchandise information
  9.     System.out.println(goods1);  
  10.     System.out.println(goods2);  
  11.       
  12.     //Update Commodity Information 1
  13.     goods1.setStatus(2);//Modify status 2
  14.     int updateResult1 = this.goodsDao.updateGoodsUseCAS(goods1);  
  15.     System.out.println("Modification of Commodity Information 1"+(updateResult1==1?"Success":"fail"));  
  16.       
  17.     //Update Commodity Information 2
  18.     goods1.setStatus(2);//Modify status 2
  19.     int updateResult2 = this.goodsDao.updateGoodsUseCAS(goods1);  
  20.     System.out.println("Modifying Commodity Information 2"+(updateResult2==1?"Success":"fail"));  
  21. }  

Output results:

  1. good id:1,goods status:1,goods name: props, goods version:1
  2. good id:1,goods status:1,goods name: props, goods version:1
  3. Successful revision of commodity information 1
  4. Failure to modify Commodity Information 2

Explain:

In the Goods DaoTest test test method, we find the same version of data at the same time, assign different goods objects, then modify the good1 object first, then perform the update operation, and perform successfully. Then we modify goods2 to indicate that the update operation failed. At this point, the data in the t_goods table is as follows:

  1. mysql> select * from t_goods;  
  2. +----+--------+------+---------+  
  3. | id | status | name | version |  
  4. +----+--------+------+---------+  
  5. |  1 |      2 | Prop |       2 |  
  6. |  2 |      2 | equipment |       2 |  
  7. +----+--------+------+---------+  
  8. rows in set  
  9.   
  10. mysql>   

We can see that the version with id 1 has been modified to 2 in the first update. So when we update good2, the update where condition does not match, so the update will not succeed. Specific sql is as follows:

  1. update t_goods   
  2. set status=2,version=version+1  
  3. where id=#{id} and version=#{version};  

In this way, we can achieve optimistic lock.

From: http://chenzhou123520.iteye.com/blog/1863407

Keywords: Java MySQL Database Mybatis xml

Added by motofzr1000 on Fri, 12 Jul 2019 20:39:07 +0300