尽管使用 Django 的原子事务和 select_for_update 仍遇到竞争条件

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

尽管实现了原子事务并利用了 select_for_update 方法,但我在 Django 应用程序中遇到了竞争条件。以下是问题的概述以及我迄今为止采取的步骤:

问题: 我有两个 Django 模型:Transaction 和 Account,其中 Transaction 实例影响关联 Account 实例的余额。然而,由于交易规模较大,我遇到了竞争条件,导致错误的结果和不正确的余额更新。

数据库架构:

Transaction:
    id (Primary Key)
    amount
    account_id (Foreign Key referencing Account.id)

Account:
    id (Primary Key)
    balance

采取的步骤

  1. 原子事务:我使用

    @transaction.atomic
    装饰器或 transaction.atomic 上下文管理器将代码中涉及数据库操作的关键部分包装在 Django 原子事务中。

  2. 行级锁定:我使用

    select_for_update
    方法在读取期间锁定Account表中的行,确保并发事务不会干扰彼此的更新。

尽管实施了这些措施,我仍然遇到竞争条件,导致余额计算不正确和数据不一致。

其他背景

我的 Django 应用程序使用 PostgreSQL 数据库。 当多个交易尝试同时更新相关帐户的余额时,似乎会出现竞争条件。 我已经验证我的代码的关键部分确实封装在原子事务中,并且

select_for_update
得到了适当的应用。

问题: 我应该采取哪些额外步骤或注意事项来缓解 Django 应用程序中的竞争条件?尽管使用原子事务和行级锁定,是否存在可能导致此问题的常见陷阱或被忽视的因素?任何见解或建议将不胜感激。

python django postgresql transactions race-condition
1个回答
0
投票

我发现解决方案是在实际业务逻辑执行之前添加一个验证,检查帐户/余额的所有权。

按照以下步骤避免竞争情况:

  1. 从账户中获取当前交易。
  2. 使用
    select_for_update
  3. 锁定帐户以进行余额转账
  4. 检查
    validation
    当前交易是否等于
    account.transaction
  5. 转账金额变更余额。
  6. 将当前交易存储到帐户。

如果发起多个交易,那么它将锁定,然后验证是否相同,然后才继续进行。

这是为了更好的直觉的图像 enter image description here

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