Как добиться согласованности базы данных при переписывании разделов таблицы?

У меня есть простая связь с базой данных: один 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.

1 ответ

Решение

Как указано в комментариях к вопросу, одним из решений Django/Postgres является использование select_for_update() на должном Item грести, прежде чем возиться с детьми. Это заставляет 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, ...)
Другие вопросы по тегам