【问题标题】:How do I achieve database consistency when rewriting sections of a table?重写表的部分时如何实现数据库一致性?
【发布时间】:2014-10-18 23:03:14
【问题描述】:

我有一个简单的数据库关系:一个 Item 与多个 ItemDetails 相关。 ItemDetails 会立即更新:一条消息通过 HTTP POST 传入,其中包含完整的 ItemDetails 集,以替换任何旧的 ItemDetails。我使用的逻辑是这样的:

with transaction.atomic():
    ...
    ItemDetails.objects.filter(item_id=item_id).all().delete()
    for item in new_item_list:
        ItemDetails.objects.create(title=item.title, ...)

但是如果两个发件人同时发送更新,这似乎有一个竞争条件。我有时会看到重复的列表,因为(我认为)delete() 在或多或少并行的两个线程上运行,然后创建发生。

我可以使用什么锁定策略来避免这个问题?我正在使用 Django 和 PostgreSQL。

【问题讨论】:

  • 你知道SELECT FOR UPDATE吗?您应该锁定父项,进行更新并提交事务。
  • 我没有,但我现在做了,看起来很完美。把它写成答案,测试后我会接受。
  • 我并不急需积分。如果您有时间随意编写并接受它 - 无论如何它会更好地解释动机+解决方案。

标签: django postgresql django-orm database-locking


【解决方案1】:

正如问题 cmets 中所指出的,一种 Django/Postgres 解决方案是在与孩子们搞乱之前在正确的 Item 行上使用 select_for_update()。这会导致 Django 阻塞等待锁。因此,将逻辑更改为以下可以修复竞争条件:

with transaction.atomic():
    # Just add this and Django will block here until other threads let go.
    item = Item.objects.select_for_update().get(pk=item_id)
    ...
    ItemDetails.objects.filter(item_id=item_id).all().delete()
    for item in new_item_list:
        ItemDetails.objects.create(title=item.title, ...)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-04-20
    • 1970-01-01
    • 1970-01-01
    • 2015-07-22
    • 2020-04-09
    • 2019-08-19
    • 2013-03-25
    • 1970-01-01
    相关资源
    最近更新 更多