MySQL'选择更新'行为

Pra*_* M 28 mysql locking transactions

根据MySql文档,MySql支持多粒度锁定(MGL).

情况1

打开终端1:

//连接到mysql

mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)

mysql> select id, status from tracking_number limit 5 for update;
+----+--------+
| id | status |
+----+--------+
|  1 |      0 |
|  2 |      0 |
|  3 |      0 |
|  4 |      0 |
|  5 |      0 |
+----+--------+
5 rows in set (0.00 sec)
mysql> 
Run Code Online (Sandbox Code Playgroud)

把它打开并打开终端2:

//连接到mysql

mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)

mysql> select id, status from tracking_number limit 5 for update;

<!-- Hangs here. and after some time it says-->
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
Run Code Online (Sandbox Code Playgroud)

虽然有很多行需要检索,但T2会等到t1完成.

情形2中

左端子1原样.现在在端子-2中:

mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)

<!-- case 2.1 -->
mysql> select id, status from tracking_number where id=1;
+----+--------+
| id | status |
+----+--------+
|  1 |      0 |
+----+--------+
1 row in set (0.00 sec)

mysql> select id, status from tracking_number where id=2;
+----+--------+
| id | status |
+----+--------+
|  2 |      0 |
+----+--------+
1 row in set (0.00 sec)

<!-- case 2.2 -->
mysql> select * from tracking_number where id=2 for update;
<!-- Hangs here. and after some time -->
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
Run Code Online (Sandbox Code Playgroud)
  1. 但是为什么在情况1中,T2等待T1锁定的同一组行?

  2. 这是否意味着无限制的选择查询(即使使用limint参数.我也尝试过不同的范围)阻止整个表?

  3. 有没有办法让事务独立锁定而不指定记录的字段(即,不使用where field = value)?
  4. 通常(或者根据Java并发锁定),写锁是独占的而读不是.在案例2.1中,虽然记录处于写锁定模式,T2如何读取相同的记录?既然这是允许锁定它的重点是什么?
  5. 案例2.2被理解.

开通终端和交易:

mysql> update tracking_number set status=4 where status=0 limit 5;
Query OK, 5 rows affected (0.00 sec)
Rows matched: 5  Changed: 5  Warnings: 0
Run Code Online (Sandbox Code Playgroud)

把它留在那里并打开另一个终端和交易:

mysql> update tracking_number set status=5 where status=0 limit 5; 
Run Code Online (Sandbox Code Playgroud)

在我提交(或回滚)T1之前,T2没有成功.

  1. 为什么会这样?

rav*_*nur 24

让我来看看你的案例并解释这些锁是如何工作的:

1例

T1想要更新测试表中的某些行.此事务将IX锁定放在所有表上,并将X锁定放在前5行上.

T2想要更新测试表中的某些行.此事务将IX(因为IX与IX兼容)锁定在所有表上并尝试前5行但由于X与X不兼容而无法执行此操作

所以我们没事.

2.1案例

T1想要更新测试表中的某些行.此事务将IX锁定放在所有表上,并将X锁定放在前5行.

T2想要从测试表中选择一些行.并且它没有放置任何锁(因为InnoDB提供非锁定读取)

2.1案例

T1想要更新测试表中的某些行.此事务将IX锁定放在所有表上,并将X锁定放在前5行.

T2想要从测试表中更新(选择更新)某些行.将IS放在整个表上并尝试对该行进行S锁定并失败,因为X和S不兼容.


还要始终注意隔离级别:不同级别会导致不同的机制来释放/获取锁定

希望能帮助到你

  • 答案为+1.虽然存在轻微的不准确性."select for update"尝试获取(IX)锁定表并(X)锁定指定的行.(见最后一句) (2认同)