sending the same request at the same time
REQUESTS DO NOT ALWAYS WORK IN PARALLEL
It depends on the database engine. In MyISAM, almost every request receives a table-level lock, which means that requests are launched sequentially as a queue. With most other engines, they can work in parallel.
echo_me says nothing happens at the exact same time and a CPU does not do everything at once
This is not entirely true. It is possible that a DBMS can work on a machine with more than one processor and with several network interfaces. It is very unlikely that 2 requests can appear simultaneously, but not impossible, therefore there is a mutex that guarantees that the transition to the session / execution is performed only as a single thread (execution is not necessarily the same light weight).
There are 2 approaches to solving coincident DML - either to use transactions (when each user effectively receives a database clone), and when the queries are completed, the DBMS tries to combine any changes - if the reconciliation fails, then the DBMS throws back one of the requests and reports that it does not work. Another approach is to use row level locking - the DBMS identifies the rows that will be updated by the request and marks them as reserved for updates (other users can read the original version of each row, but any attempt to update the data will be blocked until the row will be available again).
Your problem is that you have two mysql clients, each of which received the fact that there was one stock item left. This is further complicated by the fact that (since you mention PHP) the inventory levels may have been obtained at a different DBMS session than the subsequent inventory adjustment - you cannot have a transaction that spans more than an HTTP request. Therefore, you need to review any fact supported outside the DBMS in one transaction.
An optimistic lock can create a pseudo-transaction control mechanism - you mark a record that you intend to change using a timestamp and user ID (with a PHP session identifier, PHP is a good choice) - if, when you come in to change it, something else changed it, then your code knows that the data received earlier is invalid. However, this can lead to other complications.
source share