蓝海航行家
发布于

如何在 MySQL 中模拟丢失的更新?

我使用的是 MySQL 8.0 版本。我正在尝试模拟丢失的更新事务并发问题。这是初始表格。

  +----+--------------+----------------+
| Id | Product_Name | Items_In_Stock |
+----+--------------+----------------+
|  1 | iPhone 16    |             10 |
|  2 | Dell Laptop  |             20 |
+----+--------------+----------------+

在单独的会话/MySQL 服务器实例中运行两个事务。首先,我同时运行事务 1,然后运行事务 2。 第 1 节:

  set session transaction isolation level read committed;
start transaction;
set @itemsInStock = (select items_in_stock from inventory where id = 1);
-- Transaction takes 10 seconds.
select sleep(10);
set @itemsInStock = @itemsInStock-1;
update inventory set items_in_stock = @itemsInStock where id = 1;
select @itemsInStock;
commit;

第 2 节:

  set session transaction isolation level read committed;
start transaction;
set @itemsInStock = (select items_in_stock from inventory where id = 1);
-- Transaction takes 1 second.
select sleep(1);
set @itemsInStock = @itemsInStock-2;
update inventory set items_in_stock = @itemsInStock where id = 1;
select @itemsInStock;
commit;

希望事务 2 先完成,因为它的计时器在事务 1 之前过期。但在实践中,事务 2 被阻止,直到事务 1 完成。然后事务 2 成功更新了表 'inventory',但事务 1 给出了错误:

错误代码:1213。尝试获取 lock 时发现 deadlock;

不明白在更新之前,事务 1 中的行是如何被锁定的。这是怎么回事呢?

浏览 (27)
点赞 (1)
收藏
1条评论
Klustron小助手
Klustron小助手
试试这个 set @itemsInStock = (select items_in_stock from inventory where id = 1); MySQL 中任何将数据设置为副作用的读取查询都是锁定读取。 这包括从 SELECT 的结果中设置用户变量。 锁定读取设置共享锁,因此两个事务都可以执行 SELECT,现在都持有共享锁。 然后一个事务尝试 UPDATE,这需要排他锁。它无法获得排他锁,因为另一个事务持有共享锁。所以它等待着。 然后另一个事务也尝试 UPDATE。第一个事务持有共享锁并正在等待其独占锁。所以第二个事务也等待。 这将触发死锁检测。两个事务都在等待另一个事务,这意味着它们无法继续。因此,一个事务被终止,其锁被释放。
点赞
评论