找不到 MySQL 丢失更新问题的解决方案
Posted
技术标签:
【中文标题】找不到 MySQL 丢失更新问题的解决方案【英文标题】:Cannot find solution to MySQL Lost Update Problem 【发布时间】:2021-07-07 02:41:07 【问题描述】:我正在尝试修复 mysql 中的丢失更新问题,其中两个会话不会相互更新。基本上,问题如下:
A owes B $30. Later, A owes B another $20. In the end A needs to owe both $30 and $20, where A eventually has 50 and B has 150.
我打开了两个终端会话,但不确定如何解决并发问题。我已经搜索了所有内容以找到解决方案,但没有运气,我怎么能让 A 和 B 数字在两个会话中得到相同的结果。
以下是我从两个终端会话中获取的分步过程。
会话 A:
UPDATE accounts SET balance = 100;
SELECT * FROM accounts;
START TRANSACTION;
SELECT balance INTO @user1_balance from accounts where id = 1;
SELECT balance INTO @user2_balance from accounts where id = 2;
SELECT @user1_balance, @user2_balance;
会话 B:
START TRANSACTION;
SELECT balance INTO @user1_balance from accounts where id = 1;
SELECT balance INTO @user2_balance from accounts where id = 2;
SELECT @user1_balance, @user2_balance;
会话 A:
UPDATE accounts
SET balance = @user1_balance - 30
WHERE id = 1;
UPDATE accounts
SET balance = @user2_balance + 30
WHERE id = 2;
COMMIT;
SELECT * FROM accounts;
会话 B:
SELECT * FROM accounts;
会话 B:
UPDATE accounts
SET balance = @user1_balance - 20
WHERE id = 1;
UPDATE accounts
SET balance = @user2_balance + 20
WHERE id = 2;
COMMIT;
SELECT * FROM accounts;
如果我运行这些
【问题讨论】:
【参考方案1】:鉴于您的设置方式,丢失更新是不可避免的。问题是将余额选择为一个变量,然后用于更新表中的余额。
这在生产环境中不会发生,因为不需要为以后存储余额。
如果您将更新作为事务的一部分直接应用,那么一切都应该是一致的:
A 航站楼:
START TRANSACTION;
UPDATE accounts set balance = balance -30 where id = 1;
UPDATE accounts set balance = balance +30 where id = 2;
B 航站楼:
START TRANSACTION;
UPDATE accounts set balance = balance -20 where id = 1;
-- This update is blocked by the outstanding COMMIT on terminal A. Terminal B waits
A 航站楼:
COMMIT;
B 航站楼:
-- The COMMIT on Terminal A unlocks the rows, so we can complete our update.
UPDATE accounts set balance = balance +20 where id = 2;
COMMIT;
现在两个终端显示相同的结果:
select * from accounts;
+----+---------+
| id | balance |
+----+---------+
| 1 | 50.00 |
| 2 | 150.00 |
+----+---------+
【讨论】:
【参考方案2】:您不必运行SELECT
来分配用户余额。可以在UPDATE
完成
UPDATE accounts
SET balance = balance - 20
WHERE id = 1;
注意balance = balance - 20
。
【讨论】:
以上是关于找不到 MySQL 丢失更新问题的解决方案的主要内容,如果未能解决你的问题,请参考以下文章