Является ли get_or_create () потокобезопасным

У меня есть модель Django, доступ к которой можно получить только с помощью get_or_create (session = session) , где session - это внешний ключ для другого Django. модель.

Поскольку я получаю доступ только через get_or_create () , я могу представить, что у меня будет только один экземпляр с ключом к сеансу. Однако я нашел несколько экземпляров с ключами к одному и тому же сеансу. Что случилось? Это состояние гонки, или get_or_create () работает атомарно?

29
задан Mantas Vidutis 20 June 2011 в 19:14
поделиться

2 ответа

У меня была эта проблема с целью, которая называет get_or_create.

Я использовал Gunicorn с несколькими рабочими, поэтому, чтобы проверить его, я изменил количество рабочих на 1, и это заставило проблему исчезнуть.

Самое простое решение, которое я нашел, было заблокировать стол для доступа. Я использовал этот декоратор для блокировки каждого представления (для PostgreSQL):

http://www.caktusgroup.com/blog/2009/05/26/explicit-table-locking-with- postgresql-and-django /

РЕДАКТИРОВАТЬ: я обернул оператор блокировки в этом декораторе в попытке / кроме, чтобы иметь дело с механизмами БД без его поддержки (SQLite во время модульного тестирования в моем случае):

try:
    cursor.execute('LOCK TABLE %s IN %s MODE' % (model._meta.db_table, lock))
except DatabaseError: 
    pass
0
ответ дан 28 November 2019 в 01:20
поделиться

НЕТ, get_or_create не является не атомарным .

Сначала запрашивается DB, существует ли удовлетворительная строка; база данных возвращается, Python проверяет результаты; если он не существует, он создает его. Между get и create может произойти все что угодно - и строка, соответствующая критериям get, будет создана каким-то другим кодом.

Например, к вашей конкретной проблеме, если пользователь открывает две страницы (или выполняется несколько запросов ajax) одновременно, это может привести к сбою всех get, и для всех них create a новый ряд - с той же сессией.

Таким образом, важно использовать только get_or_create , когда проблема дублирования будет обнаружена базой данных через некоторые unique / unique_together , так что, даже если несколько потоки могут добраться до точки save (), только один из них будет успешным, а другие вызовут ошибку IntegrityError, с которой вы можете поймать и разобраться.

Если вы используете get_or_create с (набором) полей, которые не являются уникальными в базе данных, вы создадите дубликаты в вашей базе данных, что редко бывает тем, что вам нужно.

В общем, больше: не полагайтесь на свое приложение для обеспечения уникальности и избегайте дубликатов в вашей базе данных! Это работа с базой данных! (хорошо, если вы не заключите свои критические функции в некоторые блокировки, действительные для ОС, но я все равно рекомендую использовать базу данных).

С этими предупреждениями, используемыми правильно get_or_create, это легко читаемая, легко записываемая конструкция, которая идеально дополняет проверки целостности базы данных.

Ссылки и цитаты:

41
ответ дан 28 November 2019 в 01:20
поделиться
Другие вопросы по тегам:

Похожие вопросы: