Я реализую импортер, использующий пул рабочих (на основе Celery и RabbitMQ). Импортируемые данные включают пользовательские данные, идентифицируемые уникальным идентификатором пользователя, и сохраняются в базе данных PostgreSQL.
Обычно я получаю много файлов импорта, и эти файлы обрабатываются одновременно. В нескольких файлах могут быть данные для одного и того же идентификатора пользователя. Это приводит к ситуации, когда два импорта пытаются обрабатывать данные для одного и того же идентификатора пользователя одновременно.
Если данные для определенного идентификатора пользователя уже существуют, проблем нет: строка базы данных блокируется с помощью SELECT ... FOR UPDATE
. Однако, если нет данных, связанных с идентификатором, оба импорта могут столкнуться с неприятной ситуацией, когда оба пытаются INSERT
— использовать один и тот же идентификатор пользователя.
Поскольку поле идентификатора пользователя имеет ограничение UNIQUE
, транзакции не выполняются.
Как я могу предотвратить это? Есть ли другие варианты, кроме блокировки всей таблицы?
INSERT
выполнить обе одновременно, где одна, конечно, всегда терпит неудачу. Это происходит потому, что я не знаю надежного способа блокировки этой операции, например: Блокировать любые будущиеINSERT
операции, которые пытаются вставить с идентификатором пользователя = 1234. - person stschindler   schedule 02.06.2016update_or_create()
(илиget_or_create()
). Если у вас есть ограничение уникальности идентификатора пользователя, оно будет атомарным. См. этот ответ для хорошего описания. - person Kevin Christopher Henry   schedule 02.06.2016