我使用的是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 中的行是如何被锁定的。有从事过数据库和事务工作的人可以帮助我吗?
这是一个锁定读取:
set @itemsInStock = (select items_in_stock from inventory where id = 1);
MySQL 中任何将数据设置为副作用的读取查询都是锁定读取。
这包括根据 SELECT 结果设置用户变量。
锁定读取设置共享锁,因此两个事务都可以执行其 SELECT,现在都持有共享锁。
然后一个事务尝试更新,这需要排他锁。它无法获得独占锁,因为其他事务持有共享锁。所以就等着吧。
然后另一个事务也尝试更新。第一个事务持有共享锁并正在等待其独占锁。所以第二笔交易也等待。
这会触发死锁检测。两笔交易都在等待另一笔交易,这意味着它们无法继续。这样一个事务就终止了,它的锁也被释放了。