Remember the concurrent processing of different applications, using mysql transactions and row locks

Taking advantage of mysql features

isolation level

First of all, the database is 5.6.70, and the default isolation level is Repeatable Read. The database isolation level is Repeatable Read.
After the transaction starts until it ends, the same value is always read.

row lock

Update has row locks by default. Mysql update locks rows or tables.

Project requirements background

The original sign-in activity prize instance and coupon instance generate consumption logic

  • Originally, prize instances and coupon instances were generated by the backend after the event was successfully reviewed.
  • The user check-in request interface binds the prize instance and the coupon instance. The inventory is reduced by one. The method is to query first, reduce the code by one, and then update.

It is now necessary to add prize instances and coupon instances for the sign-in event.

  • When generated in the background, consumption is carried out on the interface side, and the newly generated coupon is bound. This is not good, and there may be unknown problems. However, because of the existence of the transaction, it will not be generated until the end of the transaction. will be read, so don't worry
  • Inventory concurrency problem : After the instance is generated in the background, the original inventory is increased, but the interface may also reduce the inventory.

Solution

Method 1: Not advisable

Add redis locks to both sides, increase them respectively, and finally update. Due to the existence of the lock, only one statement is operating this inventory.

The following is pseudo code

后台事务A{

​	redis锁A{
​			select stock;
			stock=stock+N;
​			update  stock=xx where id=1;
​	}

}



接口事务B{

​	redis锁A{
​			select stock;
			stock=stock-1;
​			update  stock=xx where id=1;
​	}

}

It was a good idea, but when I thought about it more carefully, I found that there were loopholes.

  1. The moment redis lock A of background transaction A is executed, the transaction has not yet been submitted.
  2. The redis lock A of interface transaction B starts to be executed. The inventory queried at this time is not the latest after the update of background transaction A.
  3. At this time, background transaction A has also been executed, and the inventory has changed.
  4. When interface transaction B is executed to update, the inventory updated by background transaction A will be overwritten, which will cause the data to become dirty.

Method 2: Desirable

Just use the row lock feature of mysql update mentioned above. You can also use update, but you don’t need to query it in the code and add it
directly in the background of additions and deletions. Since the id is the index, the row will be locked instead of the table.

UPDATE stockTable a SET a.currentInventory = a.currentInventory + N WHERE a.id = 1

The interface determines that the inventory is greater than 0 and directly decreases it by 1. The code here can determine whether the collection is successful based on the updated number of rows.

UPDATE stockTable a SET a.currentInventory = a.currentInventory - 1 WHERE a.id = 1 AND a.currentInventory > 0

This is very convenient and simple, and you don’t even need to add a distributed lock.

Guess you like

Origin blog.csdn.net/Fire_Sky_Ho/article/details/120229922