MySql pessimistic lock summary and practice

Summary and practice of pessimistic locking of mysql (for update)

https://blog.csdn.net/zmx729618/article/details/52701972
Pessimistic lock, as its name implies, refers to the modification of data by the outside world (including other current transactions of the system, as well as transactions from external systems) Be conservative, therefore, keep the data locked during the entire data processing process. The implementation of pessimistic locks often relies on the locking mechanism provided by the database (only the locking mechanism provided by the database layer can truly guarantee the exclusivity of data access. Otherwise, even if the locking mechanism is implemented in this system, it cannot be guaranteed that the external system will not be modified. data).

  使用场景举例:以MySQL InnoDB为例, 商品goods表中有一个字段status,status为1代表商品未被下单,status为2代表商品已经被下单,那么我们对某个商品下单时必须确保该商品status为1。假设商品的id为1。

1 If the lock is not used, then the operation method is as follows:

//1. Query product information

select status from t_goods where id=1;

//2. Generate an order based on the product information

insert into t_orders (id,goods_id) values (null,1);

//3. Modify the product status to 2

update t_goods set status=2;

The above scenario is likely to have problems in the case of high concurrent access.

As mentioned earlier, an order for this product can only be placed when the goods status is 1. In the first step above, the queried product status is 1. However, when we perform the third step of the Update operation, it is possible that other people place an order for the product and change the goods status to 2, but we do not know that the data has been modified, which may cause the same product to be changed. Ordered 2 times, making the data inconsistent. So this way is not safe.

2 Use pessimistic locking to achieve:

In the above scenario, there is a process of processing the order from the query to the modification of the product information. The principle of using pessimistic locking is that when we query the goods information, we will lock the current data until we finish the modification. Unlock. Then in this process, because the goods are locked, there will be no third party to modify them.

Note: To use pessimistic locking, we must turn off the autocommit attribute of the mysql database, because MySQL uses autocommit mode by default, that is, when you perform an update operation, MySQL will immediately submit the result.

We can set MySQL to non-autocommit mode with the command:

set autocommit=0;

After setting up autocommit, we can perform our normal business. details as follows:

//0. Start transaction

begin;/begin work;/start transaction; (choose one of the three)

//1. Query product information

select status from t_goods where id=1 for update;

//2. Generate an order based on the product information

insert into t_orders (id,goods_id) values (null,1);

//3. Modify the product status to 2

update t_goods set status=2;

//4. Commit transaction

commit;/commit work;

Note: The above begin/commit is the start and end of the transaction, because we turned off mysql's autocommit in the previous step, so we need to manually control the commit of the transaction, so we won't detail it here.

In the first step above, we performed a query operation: select status from t_goods where id=1 for update;

Unlike ordinary queries, we use the method of select...for update, which implements pessimistic locking through the database. At this time, in the t_goods table, the data with the id of 1 is locked by us, and other transactions can only be executed after the transaction is committed. This way we can ensure that the current data will not be modified by other transactions.

Note: It should be noted that in a transaction, only SELECT ... FOR UPDATE or LOCK IN SHARE MODE will wait for the end of other transactions before executing the same data, and generally SELECT ... is not affected by this. Take the above example, when I execute select status from t_goods where id=1 for update; after. If I execute select status from t_goods where id=1 for update; in another transaction, the second transaction will always wait for the commit of the first transaction, and the second query is blocked at this time, but if I am Execute select status from t_goods where id=1; in the second transaction, the data can be queried normally and will not be affected by the first transaction.

Added: Row Lock and Table Lock of MySQL select...for update

We mentioned above that using select...for update will lock the data, but we need to pay attention to some lock levels. MySQL InnoDB defaults to Row-Level Lock, so MySQL will only execute Row lock ( Lock only the selected data), otherwise MySQL will perform Table Lock (to lock the entire data table).

for example:

The database table t_goods includes three fields: id, status, and name. The id is the primary key. The records in the database are as follows;

Sql code collection code
mysql> select * from t_goods;
+----+--------+------+
| id | status | name |
+----+---- ----+------+
| 1 | 1 | Items |
| 2 | 1 | Equipment |
+----+--------+------+
2 rows in set

mysql>
Note: In order to test the database lock, I use two consoles to simulate different transaction operations, which are represented by console1 and console2 respectively.

Example 1: (Explicitly specify the primary key and have this data, row lock)

console1: The query results, but the data is 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 blocked

Sql code collection code
mysql> select * from t_goods where id=1 for update;
console2: If console1 has not been submitted for a long time, an error will be reported

Sql代码 收藏代码
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 there is no such data, there is 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, and the query is not blocked, 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 the data of name=prop, the query is 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 the data of name=equipment, the query is blocked, indicating that console1 has locked the table

Sql code collection code
mysql> select * from t_goods where name='equipment' for update;
console2: If console1 has not been submitted 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 is ambiguous, table lock)

console1: the query is normal

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 | 道具 |
| 2 | 1 | 装备 |
+----+--------+------+
2 rows in set

mysql>
console2: The query is blocked, indicating that console1 has locked the table

Sql code collection code
mysql> select * from t_goods where id>1 for update;

Example 5: (Primary key is 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 | 装备 |
+----+--------+------+
1 row in set

mysql>
console2: The query is blocked, indicating that console1 has locked the table

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: After the console1 transaction is committed, the console2 query result is normal

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. It should be noted that in addition to the primary key, the use of indexes will also affect the lock level of the database.

Example:

We modify the t_goods table and create an index for the status field

Modify the status of the data whose id is 2 to 2. At this time, the data in the table is:

Sql code collection code
mysql> select * from t_goods;
+----+--------+------+
| id | status | name |
+----+---- ----+------+
| 1 | 1 | Items |
| 2 | 2 | Equipment |
+----+--------+------+
2 rows in set

mysql>

Example 6: (Explicitly specify the index, and have 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: Blocks when querying data with status=1, and returns 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 the data with status=2, it can be queried normally, indicating that console1 only locks the row, not 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 specify the index, if there is no such data, there is no lock)

console1: query the data of status=3, return empty data

Sql code collection code
mysql> select * from t_goods where status=3 for update;
Empty set
console2: query the data of status=3, return empty data

Sql code collection code
mysql> select * from t_goods where status=3 for update;
Empty set

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324980258&siteId=291194637