Postgresql 如果插入依赖于以前的记录,如何处理对数据库的并发插入?

Postgresql 如果插入依赖于以前的记录,如何处理对数据库的并发插入?,postgresql,concurrency,transactions,ef-core-2.2,Postgresql,Concurrency,Transactions,Ef Core 2.2,我正在设计一种小型银行系统(将有“信用卡”,而不是真正的货币)。若用户有新的事务,我希望某种TransactionLog表获得一条记录,但我需要该记录必须包含字段“CreditsBefore”和“CreditsAfter” 考虑到情况: UserId | Transaction | CreditsBefore | CreditsAfter 1 | +20 | 0 | 20 1 | +5 | 20

我正在设计一种小型银行系统(将有“信用卡”,而不是真正的货币)。若用户有新的事务,我希望某种TransactionLog表获得一条记录,但我需要该记录必须包含字段“CreditsBefore”和“CreditsAfter”

考虑到情况:

UserId | Transaction | CreditsBefore | CreditsAfter
1      | +20         | 0             | 20
1      | +5          | 20            | 25
假设用户“1”有2个新事务。预期结果是:

UserId | Transaction | CreditsBefore | CreditsAfter
1      | +20         | 0             | 20
1      | +5          | 20            | 25
1      | +10         | 25            | 35
1      | +100        | 35            | 135
但如果它们同时执行,我们最终可能会:

UserId | Transaction | CreditsBefore | CreditsAfter
1      | +20         | 0             | 20
1      | +5          | 20            | 25
1      | +10         | 25            | 35
1      | +100        | 25 [bug]      | 125 [bug]
我知道我可以使用表锁,但是我不想锁定整个表(它可能包含数百万条记录,用于数千个用户)

是否有可能仅为“id为1的用户的所有记录”锁定表? 或者是否有其他模式来处理上述场景


我正在使用EF Core和PostgreSQL。

不确定这在您的ORM中是什么样子,但最简单的技术是

  • “悲观锁定”

    在事务开始时,使用锁定行(而不是整个表)

    然后,尝试修改同一帐户的事务被序列化,并且不会发生异常

  • 另一种选择是使用“乐观锁定”

    这是使用
    可重复读取
    事务最方便的方法。如果两个事务同时尝试读取并修改同一帐户,其中一个事务将收到序列化错误

    您的软件必须准备好重复接收序列化错误的事务

哪种方法更好取决于

  • 数据库API对这些方法的支持程度

  • 您预计碰撞的频率

    对于频繁的冲突,悲观锁定更好,因为它避免了频繁重复事务的需要(以更多锁定为代价)

  •   SELECT ... FOR UPDATE