确保事务表中的余额一致性 - PostgreSQL

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

核心银行应用程序中,我们有一个名为交易的表,其中包括列金额余额。在高并发数据插入环境中,我想通过添加以下值来更新余额列:当前金额 + 上一条记录的余额

示例:

表:交易

id 金额 平衡
1 100.00 100.00
2 50.00 150.00
3 30.00 180.00

我们尝试使用下面的触发器来实现这一目标。但是,当运行多个进程创建新事务时,结果会变得不一致。

CREATE OR REPLACE FUNCTION update_balance() RETURNS TRIGGER AS $$
BEGIN
    UPDATE transactions
    SET balance = NEW.amount + COALESCE((SELECT balance FROM transactions WHERE id = NEW.id - 1), 0)
    WHERE id = NEW.id;
    RETURN NEW;
END;
$$ LANGUAGE plpgsql;

CREATE TRIGGER update_balance_trigger
AFTER INSERT ON transactions
FOR EACH ROW
EXECUTE FUNCTION update_balance();

我们正在考虑对更新过程进行排队,但担心这不会解决一致性问题并可能会降低性能。

如何才能同时保持一致性和性能?

postgresql transactions banking
1个回答
0
投票

Oracle 有一项功能,您可以“锁定计划更新的行”,以保持数据完整性。阅读后我发现 PostgreSQL 有类似的功能和类似的语法。 从描述来看,该机制似乎是相同的,并且从我在 Oracle 中的经验来看,我们在使用它时从未出现过不一致的情况,所以我希望您在 PostgreSQL 中也不会出现任何不一致的情况。因为您正在处理余额,所以您必须等待更改,否则,使用

NOWAIT

将返回错误,并且您可能会“丢失”该余额更新请求。

关于您之前的方法,我们有使用排队方法的用户操作表(应用程序中的任何点击都会执行“某些操作”)。就性能而言,我不会说它会产生开销,不过,分析使用情况始终是最好的方法,而不是假设,但是,因为您需要对余额更新进行排队,并且如果您的客户端有很多交易,然后他们会稍后而不是实时看到他们的“真实”银行账户价值。 “稍后”是多少?这取决于(同样,您需要进行一些性能测试才能进行正确的评估)。

同时,尝试使用 FOR UPDATE OF transactions 锁定行。显然,请记住禁用触发器。

您可以尝试使用

NOWAIT
锁并仅对“丢失”的更新进行排队,因为通常您会单独更新每个帐户,因此为每个需要的帐户设置独占锁并更新和排队该帐户行是有意义的,如果它需要更多的后续更新。同样,您需要进行测试,看看将它们组合起来是否是正确的方法。


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