MySQL (for update) pessimistic lock summary and practice
52701972
Pessimistic locking, as its name implies, is a conservative attitude to the data being modified by the outside world (including other transactions currently in the system, as well as transactions from external systems), so that the data is locked during the entire data processing process. Pessimistic lock implementation, often rely on the database provided by the lock mechanism (also only the database layer provides a lock mechanism to truly guarantee the exclusivity of data access, otherwise, even in this system to implement the locking mechanism, there is no guarantee that the external system will not modify the data).
使用场景举例:以MySQL InnoDB为例, 商品goods表中有一个字段status,status为1代表商品未被下单,status为2代表商品已经被下单,那么我们对某个商品下单时必须确保该商品status为1。假设商品的id为1。
1 if the lock is not used, then the operation is as follows:
1. Check out the product information
Select status from T_goods where id=1;
2. Generate orders based on product information
Insert into T_orders (id,goods_id) values (null,1);
3. Change the item status to 2
Update t_goods set status=2;
This scenario is likely to cause problems in high concurrent access scenarios.
As mentioned earlier, only if the goods status is 1 o'clock to order the goods, the first step above, the item status of the query is 1. However, when we perform the third update operation, it is possible for others to first change the goods status to 2 for the order, but we do not know that the data has been modified, which may cause the same item to be put on the order 2 times, which makes the data inconsistent. So it's not safe to say this way.
2 Use pessimistic lock to achieve:
In the above scene, the product information from the query out to modify, in the middle there is a process of processing orders, the use of pessimistic locking principle is that when we query out goods information after the current data lock, until we modify and then unlock. So in this process, because the goods is locked, there will be no third party to modify it.
Note: To use pessimistic locks, we must turn off the auto-commit property of the MySQL database because MySQL uses the autocommit mode by default, which means that when you perform an update operation, MySQL will immediately submit the results.
We can use the command to set MySQL to non-autocommit mode:
Set autocommit=0;
After setting up the autocommit, we can execute our normal business. Specific as follows:
0. Start a transaction
Begin;/begin Work;/start Transaction; (You can choose one of the three)
1. Check out the product information
Select status from T_goods where id=1 for update;
2. Generate orders based on product information
Insert into T_orders (id,goods_id) values (null,1);
3. Change the item status to 2
Update t_goods set status=2;
4. Commit a transaction
Commit;/commit work;
Note: The above begin/commit is the start and end of the transaction, because in the previous step we closed the MySQL autocommit, so we need to manually control the commit of the transaction, here is not a detailed table.
The first step above we performed a query operation: Select status from T_goods where id=1 for update;
Unlike normal queries, we use the Select...for Update method, which enables pessimistic locking through the database. At this point in the T_goods table, the data with ID 1 is locked, and the other transaction must wait for the transaction to be committed before it can be executed. This allows us to ensure that the current data is not modified by other transactions.
Note: It is important to note that in a transaction, only select ... For UPDATE or lock in SHARE MODE the same pen data will wait for other transactions to finish before executing, general Select ... is not affected by this. Take the example above when I perform the select status from T_goods where id=1 for update; I am in another transaction if the select status from T_goods where id=1 for update is executed again, then the second transaction waits for the first transaction to commit, at which point the second query is in a blocked state. But if I was executing the select status from T_goods where Id=1 in the second transaction, the data would be queried normally and not affected by the first transaction.
Added: MySQL select...for update's Row lock and table lock
As we mentioned above, using Select...for Update will lock the data, but we need to pay attention to some lock levels, MySQL InnoDB default row-level lock, so only "explicitly" to specify the primary key, MySQL will execute row lock ( Lock only the selected data), or MySQL will execute table lock (lock the entire data form).
To illustrate:
database table T_goods, including Id,status,name three fields, the ID is the primary key, the database is recorded as follows;
SQL Code Collection Code
Mysql> select * from T_goods;
+----+--------+------+
| ID | Status | name |
+----+--------+------+
| 1 | 1 | Props |
| 2 | 1 | Equipment |
+----+--------+------+
2 rows in Set
Mysql>
Note: In order to test the database lock, I use two console to simulate different transaction operations, represented by Console1, Console2, respectively.
Example 1: (explicitly specifying a primary key and having this data, row lock)
Console1: The result was queried, but the data was locked
SQL Code Collection Code
Mysql> SELECT * from T_goods where id=1 for update;
+----+--------+------+
| ID | Status | name |
+----+--------+------+
| 1 | 1 | Props |
+----+--------+------+
1 row in Set
Mysql>
Console2: Query is blocked
SQL Code Collection Code
Mysql> SELECT * from T_goods where id=1 for update;
Console2: If Console1 is not submitted for a long time, it will report an error
SQL Code Collection Code
Mysql> SELECT * from T_goods where id=1 for update;
ERROR 1205:lock wait timeout exceeded; Try restarting transaction
Example 2: (explicitly specify the primary key, if the data is not found, no lock)
Console1: The query result is empty
SQL Code Collection Code
Mysql> SELECT * from T_goods where id=3 for update;
Empty Set
Console2: The query result is empty, the query is non-blocking, indicating that Console1 does not lock the data
SQL Code Collection Code
Mysql> SELECT * from T_goods where id=3 for update;
Empty Set
Example 3: (No primary key, table lock)
Console1: Query name= props data, query normal
SQL Code Collection Code
Mysql> SELECT * from t_goods where name= ' props ' for update;
+----+--------+------+
| ID | Status | name |
+----+--------+------+
| 1 | 1 | Props |
+----+--------+------+
1 row in Set
Mysql>
Console2: Query name= equipment data, query blocking, instructions Console1 to lock the watch
SQL Code Collection Code
Mysql> SELECT * from t_goods where name= ' equipment ' for update;
Console2: If Console1 is not committed for a long time, the query returns empty
SQL Code Collection Code
Mysql> SELECT * from t_goods where name= ' equipment ' for update;
Query OK,-1 rows affected
Example 4: (primary key ambiguous, table lock)
Console1: Query OK
SQL Code Collection Code
Mysql> begin;
Query OK, 0 rows affected
Mysql> SELECT * from T_goods where id>0 for update;
+----+--------+------+
| ID | Status | name |
+----+--------+------+
| 1 | 1 | Props |
| 2 | 1 | Equipment |
+----+--------+------+
2 rows in Set
Mysql>
Console2: The query was blocked, indicating that Console1 locked the watch.
SQL Code Collection Code
Mysql> SELECT * from T_goods where id>1 for update;
Example 5: (primary key ambiguous, table lock)
Console1:
SQL Code Collection Code
Mysql> begin;
Query OK, 0 rows affected
Mysql> SELECT * from T_goods where id<>1 for update;
+----+--------+------+
| ID | Status | name |
+----+--------+------+
| 2 | 1 | Equipment |
+----+--------+------+
1 row in Set
Mysql>
Console2: The query was blocked, indicating that Console1 locked the watch.
SQL Code Collection Code
Mysql> SELECT * from T_goods where id<>2 for update;
Console1: Commit Transaction
SQL Code Collection Code
Mysql> commit;
Query OK, 0 rows affected
Console2 query results are normal after CONSOLE2:CONSOLE1 transaction commits
SQL Code Collection Code
Mysql> SELECT * from T_goods where id<>2 for update;
+----+--------+------+
| ID | Status | name |
+----+--------+------+
| 1 | 1 | Props |
+----+--------+------+
1 row in Set
Mysql>
The above is about the impact of the database primary key on the MySQL lock level instance, it should be noted that in addition to the primary key, the use of indexes will also affect the database lock level
Example:
We modify the T_goods table to create an index to the Status field
Change the status of data with ID 2 to 2, at which time the data in the table is:
SQL Code Collection Code
Mysql> select * from T_goods;
+----+--------+------+
| ID | Status | name |
+----+--------+------+
| 1 | 1 | Props |
| 2 | 2 | Equipment |
+----+--------+------+
2 rows in Set
Mysql>
Example 6: (explicitly specified index, and there is this data, row lock)
Console1:
SQL Code Collection Code
Mysql> SELECT * from T_goods where status=1 for update;
+----+--------+------+
| ID | Status | name |
+----+--------+------+
| 1 | 1 | Props |
+----+--------+------+
1 row in Set
Mysql>
Console2: Blocking when querying Status=1 data, returning empty after timeout, indicating that the data is locked by Console1
SQL Code Collection Code
Mysql> SELECT * from T_goods where status=1 for update;
Query OK,-1 rows affected
Console2: Query status=2 data, can normal query, indicating that Console1 only locked the line, unlocked the table
SQL Code Collection Code
Mysql> SELECT * from T_goods where status=2 for update;
+----+--------+------+
| ID | Status | name |
+----+--------+------+
| 2 | 2 | Equipment |
+----+--------+------+
1 row in Set
Mysql>
Example 7: (explicitly specified index, no lock if no data is found)
Console1: Querying status=3 data, returning empty data
SQL Code Collection Code
Mysql> SELECT * from T_goods where status=3 for update;
Empty Set
Console2: Querying status=3 data, returning empty data
SQL Code Collection Code
Mysql> SELECT * from T_goods where status=3 for update;
Empty Set
MySQL pessimistic lock summary and practice