Как избежать этого состояния гонки в Python / Django / MySQL? - PullRequest
2 голосов
/ 06 сентября 2010

У меня есть модель MyModel с полем expiration_datetime.

Каждый раз, когда пользователь получает экземпляр MyModel, мне нужно сначала проверить, истек ли он или нет.Если срок его действия истек, нужно увеличить счетчик, обновить другие, а затем продлить время expiration_datetime до некоторого времени в будущем.

Таким образом, представление будет выглядеть примерно так:

if object.expiration_datetime < datetime.datetime.now(): 
    object.counter = F('counter') + 1 
    object.expiration_datetime = F('expiration_datetime') + datetime.timedelta(days=1) 
    object.save() 

В приведенном выше коде есть условие гонки.Скажем, поток 1 проверяет и находит, что текущий экземпляр истек, он продолжает увеличивать счетчик и продлевать время истечения срока.Но прежде чем он смог сделать это, поток 2 запланирован и делает то же самое.К тому времени, когда поток 1 наконец завершает свою работу, счетчик увеличивается вдвое, а время expration_datetime увеличивается вдвое.

Похоже, это должно быть довольно распространенной проблемой.Какой самый эффективный способ справиться с этим?В идеале я хотел бы иметь возможность обрабатывать его в Django с помощью переносимой базы данных.

Ответы [ 3 ]

6 голосов
/ 06 сентября 2010

Это может быть хорошим вариантом использования для оптимистической блокировки . Есть несколько способов сделать это:

  • У вас может быть номер версии, и вы выполняете запросы UPDATE, чтобы он всегда включал номер версии в предложение WHERE, а затем проверяете, были ли изменены какие-либо строки.
  • Включите каждое значение записи (до внесенных вами изменений) в предложение WHERE, чтобы вы могли быть уверены, что сохраняемая запись точно такая же, как и при ее чтении.

Как реализовать оптимистическую блокировку в Django? Проверьте этот вопрос: Джанго: Как я могу защитить от одновременного изменения записей базы данных .

3 голосов
/ 07 сентября 2010

Использовать транзакцию базы данных. Они предназначены для того, чтобы обрабатывать случаи именно так.

Если вы используете MySQL, помните, что только таблицы InnoDB поддерживают транзакции ACID, поэтому убедитесь, что в ваших таблицах используется механизм InnoDB.

0 голосов
/ 27 октября 2017

Вы также можете использовать условные выражения Case и When. Docs .

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