php solves the problem of negative inventory caused by concurrent warehousing of large traffic such as snapping up spike lottery

  • 2021-07-01 06:52:36
  • OfStack

We know that the database processing sql is processed one by one, assuming that the process of purchasing goods is like this:

sql1: Query merchandise inventory


if( Inventory quantity  > 0)
{
  // Generate an order ...
  sql2: Inventory -1
}

When there is no concurrency, the above process looks so perfect. Suppose two people place an order at the same time and there is only one inventory. In sql1, the inventory inquired by both people is > 0, so sql2 was finally implemented, and the inventory finally changed to-1, which was oversold. Either replenish the inventory or wait for the user to complain.

A popular way to solve this problem:

1. Use an extra single process to process a queue, put the order request into the queue, and process it one by one, so there will be no concurrency problem, but the extra background process and delay problem will not be considered.

2. Database optimistic lock, which roughly means to query the inventory first, then immediately +1 the inventory, and then after the order is generated, query the inventory again before updating the inventory to see if it keeps 1 with the expected inventory quantity, and roll back if it is not 1, prompting the user that the inventory is insufficient.

3. According to the result of update, we can add a judgment condition update... where inventory when sql2 > 0. If false is returned, the inventory is insufficient and the transaction is rolled back.

4. With the help of file exclusive lock, when processing the order request, lock a file with flock. If the lock fails, it means that other orders are being processed. At this time, either wait or directly prompt the user that "the server is busy"

This article is going to talk about the fourth scheme, and the approximate code is as follows:

Blocking (waiting) mode


<?php
$fp = fopen("lock.txt", "w+");
if(flock($fp,LOCK_EX))
{
  //.. Processing orders 
  flock($fp,LOCK_UN);
}
fclose($fp);
?>

Non-blocking mode


<?php
$fp = fopen("lock.txt", "w+");
if(flock($fp,LOCK_EX | LOCK_NB))
{
  //.. Processing orders 
  flock($fp,LOCK_UN);
}
else
{
  echo " The system is busy, please try again later ";
}

fclose($fp);
?>


Related articles: