【发布时间】:2021-06-14 10:51:18
【问题描述】:
我有两个这样的数据库表:
CREATE TABLE IF NOT EXISTS accounts (
id INT PRIMARY KEY NOT NULL,
balance INT NOT NULL DEFAULT 0
);
CREATE TABLE IF NOT EXISTS transactions (
from INT FOREIGN KEY REFERENCES accounts(id),
to INT FOREIGN KEY REFERENCES accounts(id),
amount INT NOT NULL
)
在我的应用程序逻辑中,每当有新的交易请求进来时,我想先检查 from 账户是否有足够的余额,然后我想从 from 账户中减去金额,将金额添加到 to 账户,然后添加事务表的新行。
但是,我想以原子方式完成所有这些工作,原因有两个:
- 防止竞争条件。如果有两个请求将 5 美元从账户 1 转移到账户 2,而账户 1 总共只有 5 美元,我想防止余额发生双重支出。因此,余额充足的检查和余额的后续更新必须以原子方式进行。
- 防止应用程序崩溃时出现不一致的状态。
是否可以在单个 SQL 语句中执行此操作?假设我们使用的是 Postgres。
我知道例如我可以通过UPDATE accounts SET balance = balance - 6 WHERE id = 1 and balance > 6; 来检查帐户是否有足够的余额并同时更新余额。
我也听说过一个叫select ... for update 的东西,但我不确定这是否能帮到我。
另外,查询的结果应该表明交易是否成功,如果不成功,我可以向客户端显示一些错误消息?
【问题讨论】:
-
假设我们正在使用 PostGres。 如果是这样,那么标记 [postgresql] 并取消标记 [mysql]。
-
@kmoser 不是真的,这只是展示了如何使用事务。这如何解决我的问题?在添加到帐户之前,我仍然需要通过某种方式检查余额是否足够
-
@shmth Transactions 允许您将多个 SQL 语句视为原子操作。这不是你想做的吗?
-
@kmoser 但我也想防止问题中提到的竞争条件。事务对此没有帮助,因为两个事务可以交错。
标签: sql postgresql