我正在学习MySQL锁,发现MDL有一些问题.

MySQL版本是8.0.

有一个使用InnoDB的名为Account的表.

第一节课:

begin; // start the transaction个个

select * from table account; // acquire the MDL SHARED_READ lock

第二节课:

alter table account add columnA int; // try to acquire the MDL EXCLUSIVE lock, wait for session 1 to release lock个个

然后,我try 在会话1中向表ACCOUNT插入一条记录,但插入的记录是MySQL tells me there is a deadlock and rollback session 1 automatically.

我try 了一些不同的东西:

第一节课:

begin; // start the transaction个个

insert into a values ('test'); // acquire the MDL SHARED_WRITE lock

第二节课:

alter table account add columnA int; // try to acquire the MDL EXCLUSIVE lock, wait for session 1 to release lock个个

Then I found it is OK to do the insert and select operations in session 1.

这真的让我很困惑,为什么我先用select操作获取MDL SHARED_READ锁导致死锁?

推荐答案

因为有不同类型的MDL共享锁,SHARED_READ和SHARED_WRITE.

session 1:个个个个

begin; // start the transaction

select * from table account; 
// acquire the MDL SHARED_READ lock

我们可以观察到这个MDL:

mysql> select object_name, lock_type, owner_thread_id from performance_schema.metadata_locks;
+----------------+--------------+-----------------+
| object_name    | lock_type    | owner_thread_id |
+----------------+--------------+-----------------+
| account        | SHARED_READ  |              64 |

session 2:个个

alter table account add columnA int; 
// try to acquire the MDL EXCLUSIVE lock, wait for session 1 to release lock

mysql> select object_name, lock_type, owner_thread_id from performance_schema.metadata_locks;
+----------------+---------------------+-----------------+
| object_name    | lock_type           | owner_thread_id |
+----------------+---------------------+-----------------+
| account        | SHARED_READ         |              64 |
| NULL           | INTENTION_EXCLUSIVE |              65 |
| NULL           | INTENTION_EXCLUSIVE |              65 |
| NULL           | INTENTION_EXCLUSIVE |              65 |
| account        | SHARED_UPGRADABLE   |              65 |
| test/account   | INTENTION_EXCLUSIVE |              65 |
| #sql-255_17    | EXCLUSIVE           |              65 |
| account        | EXCLUSIVE           |              65 |

session 1:个个个个

要执行插入操作,会话1必须获取一种新类型的MDL锁,但当会话2排队等待MDL独占锁时,它无法做到这一点.

mysql> insert into account () values ();
// try to acquire a MDL SHARED_WRITE lock
// wait for session 2 to release its queued lock request

因此,两个会话都在等待对方,两个会话都无法继续进行.这是一个僵局.

ERROR 1213 (40001): Deadlock found when trying to get lock; try restarting transaction

第二个实验:

session 1:个个个个

begin; // start the transaction

select * from table account for update; 
// acquire the MDL SHARED_WRITE lock

我们可以观察到这个MDL:

mysql> select object_name, lock_type, owner_thread_id from performance_schema.metadata_locks;
+----------------+--------------+-----------------+
| object_name    | lock_type    | owner_thread_id |
+----------------+--------------+-----------------+
| account        | SHARED_WRITE |              64 |

这是一种不同类型的MDL.它允许插入.

session 2:个个

alter table account add columnA int; 
// try to acquire the MDL EXCLUSIVE lock, wait for session 1 to release lock

与前面的实验一样,DDL语句等待.

session 1:个个个个

mysql> insert into account () values ();
Query OK, 1 row affected (0.00 sec)

不需要额外的锁.会话1已经具有执行插入所需的MDL SHARED_WRITE锁,因此它能够继续.

Mysql相关问答推荐

返回50%的随机结果

Mysql - Select 匹配某些条件的两条记录之间经过的最大天数

根据 MySql 中同一表中的多列 Select 多列

如果其中一个表为空,则 mysql 中的查询会给出 0 个结果

优化解析 5000 万行 MySQL 表的请求

如何在 MySQL 中使用从 SELECT IF 返回的布尔值

如何同时从同一个表中 Select 从 SQL 表中删除行

检索按键列值分组的最新日期 (MySql)

MySQL 将分组 JSON Select 转换为单个 JSON 对象

使用 ON DUPLICATE KEY 将列增加一定数量 MySQL NodeJS

最好的 MySQL 性能调优工具?

在 Android 上运行 AMP (apache mysql php)

你如何在 Node.js 中模拟 MySQL(没有 ORM)?

MySQL行格式:固定和动态之间的区别?

MySQL 删除多列

更改 Laravel 的 created_at 和 updated_at 的名称

我可以在 PHP 中使用 PDO 创建数据库吗?

PHP mySQL - 将新记录插入表中,主键自动递增

电话号码和地址的mysql数据类型

在 PHP 中运行 MySQL *.sql 文件