Recently, I was working on a group buying project and encountered a problem: the inventory quantity was limited during flash sales, flash sales, lottery and other activities, but at the same time the number of people who placed orders exceeded the inventory quantity, this will cause the goods to be sold out. So how can we solve this problem? My idea is as follows: we know that SQL statements are handled in a database. Suppose the process of purchasing a product is as follows:
Sql1: Query product inventory
If (inventory quantity> 0) {// generate order... sql2: inventory-1}
When there is no concurrency, the above process looks so perfect. Assume that two people place orders at the same time, and there is only one inventory. In sql1stage, the inventory queried by two people is greater than 0, therefore, SQL 2 is executed in the end, and the inventory is changed to-1 at the end. If it is sold out, you can either fill the inventory or wait for the user to complain.
A popular solution to this problem:
1. when an additional single process is used to process a queue and place an order request in the queue, there will be no concurrency issues after each process. However, additional background processes and latency issues are not considered.
2. optimistic database lock, which roughly means to query the inventory first, then immediately add inventory + 1, and then query the inventory before updating the inventory after the order is generated, check whether the inventory quantity is consistent with the expected quantity. If the inventory quantity is inconsistent, the system will roll back, prompting you that the inventory is insufficient.
3. based on the update results, we can add a judgment condition update in sql2... where inventory> 0. If false is returned, the inventory is insufficient and the transaction is rolled back.
4. with file exclusive lock, a file is locked with flock when processing the order request. If the lock fails, other orders are being processed, either waiting or prompting the user "the server is busy"
This article will talk about 4th solutions. The Code is as follows:
Blocking (wait) Mode
<? Php $ fp = fopen ("lock.txt", "w +"); if (flock ($ fp, LOCK_EX )){//.. process Order flock ($ fp, LOCK_UN);} fclose ($ fp);?>
Non-Blocking Mode
<? Php $ fp = fopen ("lock.txt", "w +"); if (flock ($ fp, LOCK_EX | LOCK_NB )){//.. process the order flock ($ fp, LOCK_UN);} else {echo "the system is busy. Please try again later";} fclose ($ fp);?>