Как избежать ошибок целостности, возникающих из-за одновременного создания / обновления? - PullRequest
0 голосов
/ 02 октября 2019

Итак, скажем, есть модель A, которая выглядит следующим образом:

class A(model):
    name = char(unique=True)

Когда пользователь пытается создать новую A, представление проверит, уже занято ли имя. Вот так:

name_taken = A.objects.get(name=name_passed_by_user)
if name_taken:
    return "Name exists!"
# Creating A here

Раньше все работало хорошо, но по мере роста системы стали появляться параллельные попытки создания А с тем же именем. И иногда несколько запросов проходят проверку «имя существует» за те же несколько миллисекунд, что приводит к ошибкам целостности, поскольку поле имени должно быть УНИКАЛЬНЫМ, а несколько запросов на создание определенного имени проходят проверку.

Текущее решение - это «try: кроме IntegrityError:», которое оборачивается вокруг частей создания, несмотря на предварительную проверку. Есть ли способ избежать этого? Поскольку существует множество моделей с такими уникальными ограничениями, таким образом, возникает много уродливых оберток «try: кроме IntegrityError:». Можно ли заблокировать, чтобы не запретить ВЫБОР, но заблокировать, чтобы предотвратить ВЫБОР ДЛЯ ОБНОВЛЕНИЯ? Или, может быть, есть более правильное решение? Я уверен, что это общая проблема с именами пользователей и другими полями / столбцами, подобными им, и должен быть правильный подход, а не перехват исключений.

БД - это Postgres10, ORM - это SQLAlchemy из Python, но настраивается наБД напрямую применимы тоже.

Ответы [ 2 ]

1 голос
/ 02 октября 2019

Если вы используете Python, вы должны были услышать о принципе дизайна «прошу прощения, а не разрешения».

Чтобы избежать описываемых вами условий гонки, просто попробуйте добавить новую строку в таблицу. Если вы получите unique_violation (SQLSTATE 23505), откатите транзакцию и верните, что имя существует.

1 голос
/ 02 октября 2019

Единственное, что вы можете сделать, это установить соответствующую изоляцию транзакции непосредственно на postgres. Ни Python, ни ORM ничего не могут с этим поделать. Уровень serialized , скорее всего, решит вашу проблему. Но это может снизить производительность, поэтому вы должны попробовать повторяемое чтение .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...