[ThinkPHP]Table Locking Under Concurrency in ThinkPHP

Recently I needed to build a registration system that doesn’t require very high concurrency, but there’s still a possibility of multiple users registering at the same time. Since registration involves ordering, without row locking or table locking, the following situation can occur.
Example:
Currently the system only has user A registered with order 1, denoted as (A, 1).
At some moment t, users B, C, and D register simultaneously. The backend receives all three requests almost at the same time, queries the registration table, finds only (A, 1), and inserts (B, 2), (C, 2), (D, 2) into the table, resulting in:

1
2
3
4
(A, 1)
(B, 2)
(C, 2)
(D, 2)

My initial idea was: instead of recording the order number, I would record the insertion timestamp, which would give:

1
2
3
4
(A, ta)
(B, tb)
(C, tc)
(D, td)

ta, tb, tc, td are almost impossible to be equal.
However, this approach has three unsolvable issues:

  1. There is a (very low) probability that timestamps could be equal
  2. It’s not intuitive and requires sorting by timestamp
  3. Registration has a capacity limit (e.g., 40 spots) and needs to immediately report whether the registration was successful

The current solution is to use database locking.
After researching online, ThinkPHP supports both pessimistic and optimistic locking. Given the low traffic of the target system, pessimistic locking is sufficient.

MyISAM can only lock tables, while InnoDB supports row-level locking. Table locking is sufficient for the target system.
The official documentation provides this table locking approach:

1
$User->lock(true)->save($data);// Use pessimistic locking

However, the target system needs to perform a series of operations, so the table locking code used is:

1
2
3
4
M()->query("lock tables yourtable write");
// TODO
// your code
M()->query("unlock tables");

The actual results worked quite well [real dates have been redacted]:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
??-??-?? 10:00:00   1
??-??-?? 10:00:00   2
??-??-?? 10:00:00   3
??-??-?? 10:00:00   4
??-??-?? 10:00:01   5
??-??-?? 10:00:01   6
??-??-?? 10:00:01   7
??-??-?? 10:00:01   8
??-??-?? 10:00:02   9
??-??-?? 10:00:02   10
??-??-?? 10:00:02   11
??-??-?? 10:00:02   12
??-??-?? 10:00:02   13
??-??-?? 10:00:02   14
??-??-?? 10:00:03   15
??-??-?? 10:00:03   16
??-??-?? 10:00:03   17
??-??-?? 10:00:05   18
??-??-?? 10:00:06   19
??-??-?? 10:00:07   20
??-??-?? 10:00:08   21
??-??-?? 10:00:10   22
??-??-?? 10:00:15   23
??-??-?? 10:00:17   24
??-??-?? 10:00:19   25
??-??-?? 10:00:19   26
??-??-?? 10:00:24   27
??-??-?? 10:00:25   28
??-??-?? 10:00:34   29
??-??-?? 10:00:35   30
??-??-?? 10:00:38   31
??-??-?? 10:01:06   32
??-??-?? 10:01:11   33
??-??-?? 10:01:11   34
??-??-?? 10:01:17   35
??-??-?? 10:01:18   36
??-??-?? 10:02:27   37
??-??-?? 10:02:38   38
??-??-?? 10:02:39   39
??-??-?? 10:02:57   40