【问题标题】:How to avoid integrity errors occuring because of concurrent creations/updates?如何避免由于并发创建/更新而发生完整性错误?
【发布时间】:2020-01-31 13:40:28
【问题描述】:

假设有一个模型 A,它看起来像这样:

class A(model):
    name = char(unique=True)

当用户尝试创建新的 A 时,视图会检查该名称是否已被占用。像这样:

name_taken = A.objects.get(name=name_passed_by_user)
if name_taken:
    return "Name exists!"
# Creating A here

它曾经运行良好,但随着系统的发展,开始出现并发尝试创建具有相同名称的 A。有时多个请求在相同的几毫秒内通过“名称存在检查”,导致完整性错误,因为名称字段必须是唯一的,并且创建某个名称的多个请求通过检查。

当前的解决方案是很多“try: except IntegrityError:”围绕创建部分,尽管事先检查。有没有办法避免这种情况?因为有很多具有这样的 UNIQUE 约束的模型,所以很多丑陋的“尝试:除了 IntegrityError:”包装。是否可以锁定以不阻止 SELECTing,但锁定以阻止 SELECTing FOR UPDATE?或者也许有更合适的解决方案?我确定这是用户名和其他类似字段/列的常见问题,必须有适当的方法而不是异常捕获。

DB 是 Postgres10,ORM 是 Python 的 SQLAlchemy,但是直接调整 db 也可以。

【问题讨论】:

    标签: python django database postgresql sqlalchemy


    【解决方案1】:

    您唯一能做的就是将适当的transaction isolation 直接设置为postgres。 python 和 ORM 都无能为力。 序列化 级别很可能会解决您的问题。但这可能会降低性能,因此您也应该尝试repeatable read

    【讨论】:

      【解决方案2】:

      如果您使用 Python,您应该听说过“请求宽恕,而不是许可”的设计原则。

      为避免您描述的竞争条件,只需尝试将新行添加到表中。 如果得到unique_violation (SQLSTATE 23505),则回滚事务并返回名称存在。

      【讨论】:

      • 谢谢,现在确实是这样,所有的 try: except:'s 和 sessions.rollback()'s。可能不应该改变它,因为它是原则之一。只是认为这是一个糟糕的设计模式。显然不是。
      猜你喜欢
      • 2011-02-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-11-13
      • 2020-03-15
      • 1970-01-01
      相关资源
      最近更新 更多