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

问题描述 投票:0回答:1

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

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

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

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;

第二场:

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 成功更新了表“库存”,但事务 1 给出了错误:

错误代码:1213。尝试获取锁时发现死锁;

我不明白更新之前事务 1 中的行是如何被锁定的。有从事过数据库和事务工作的人可以帮助我吗?

mysql database concurrency transactions deadlock
1个回答
0
投票

这是一个锁定读取

set @itemsInStock = (select items_in_stock from inventory where id = 1);

MySQL 中任何将数据设置为副作用的读取查询都是锁定读取。

这包括根据 SELECT 结果设置用户变量。

锁定读取设置共享锁,因此两个事务都可以执行其 SELECT,现在都持有共享锁。

然后一个事务尝试更新,这需要排他锁。它无法获得独占锁,因为其他事务持有共享锁。所以就等着吧。

然后另一个事务也尝试更新。第一个事务持有共享锁并正在等待其独占锁。所以第二笔交易也等待。

这会触发死锁检测。两笔交易都在等待另一笔交易,这意味着它们无法继续。这样一个事务就终止了,它的锁也被释放了。

© www.soinside.com 2019 - 2024. All rights reserved.