一尘不染

MySQL“选择更新”行为

mysql

根据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>

离开它打开并打开终端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

尽管要检索的行很多,但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
  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

离开那里,打开另一个终端和交易:

mysql> update tracking_number set status=5 where status=0 limit 5;

直到我提交(或回滚)T1,T2才成功。

  1. 为什么会这样呢?

阅读 349

收藏
2020-05-17

共1个答案

一尘不染

让我审视您的情况并解释这些锁的工作方式:

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不兼容而失败。


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

希望能帮助到你

2020-05-17