找不到 MySQL 丢失更新问题的解决方案

Cannot find solution to MySQL Lost Update Problem

我正在尝试修复 MySQL 中的丢失更新问题,其中两个会话不会相互更新。基本上,问题如下:

A owes B . Later, A owes B another . In the end A needs to owe both  and , 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;

如果我运行这些

鉴于您的设置方式,丢失更新是不可避免的。问题是将余额选择为变量,然后用于更新 table.

中的余额

这不会发生在生产环境中,因为不需要存储余额供以后使用。

如果您直接将更新作为事务的一部分进行应用,一切都应该保持一致:

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 |
+----+---------+

您不必 运行 和 SELECT 分配用户余额。可以在 UPDATE

完成
UPDATE accounts 
SET balance = balance  - 20 
WHERE id = 1;

注意 balance = balance - 20