在MySQL中,当多个事务试图同时访问同一行数据时,可能会发生锁等待。锁等待是指一个事务(T1)正在等待另一个事务(T2)释放它所需要的资源上的锁。这种情况下,T1将被挂起直到T2完成并释放了锁。

下面是一个简单的示例来展示如何在MySQL中创建锁等待的情况。我们将使用InnoDB存储引擎,因为它是唯一支持行级锁定的MySQL存储引擎之一。

准备工作

首先,确保你的数据库使用的是InnoDB存储引擎。如果需要,可以创建一个新的表:

CREATE TABLE test_lock (
    id INT NOT NULL,
    data VARCHAR(255),
    PRIMARY KEY (id)
) ENGINE=InnoDB;

插入一些初始数据:

INSERT INTO test_lock (id, data) VALUES (1, 'Initial Data');

创建锁等待

步骤1: 开启第一个事务

打开一个MySQL命令行窗口,并开始一个事务:

START TRANSACTION;

更新表中的一行数据,这将获取该行的排他锁:

UPDATE test_lock SET data = 'Data Changed by T1' WHERE id = 1;

此时,如果你查询当前会话中的锁信息,可以看到已经获得了一行记录的锁。

步骤2: 开启第二个事务

在另一个MySQL命令行窗口中开启一个新的事务:

START TRANSACTION;

尝试更新同一行数据:

UPDATE test_lock SET data = 'Data Changed by T2' WHERE id = 1;

这时,你会注意到这个命令会暂停执行,因为它正在等待第一个事务释放锁。

步骤3: 解决锁等待

回到第一个事务所在的窗口,提交事务以释放锁:

COMMIT;

现在回到第二个事务所在的窗口,你会发现原本暂停的UPDATE命令已经执行完毕,因为锁已经被释放。

检查锁等待情况

如果你想查看当前系统中存在的锁等待情况,可以使用以下查询:

SELECT r.trx_id waiting_trx_id, r.trx_mysql_thread_id waiting_thread,
       r.trx_query waiting_query, b.trx_id blocking_trx_id,
       b.trx_mysql_thread_id blocking_thread, b.trx_query blocking_query
FROM information_schema.innodb_lock_waits w
INNER JOIN information_schema.innodb_trx b ON w.blocking_trx_id = b.trx_id
INNER JOIN information_schema.innodb_trx r ON w.requesting_trx_id = r.trx_id;

此查询将列出所有当前存在的锁等待关系,包括哪些事务正在等待以及它们正在等待哪个事务释放锁。