Как добиться согласованности базы данных при переписывании разделов таблицы?
У меня есть простая связь с базой данных: один 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, ...)