Подтвердить что ты не робот

Это безопасный способ увеличения и получения значения счетчика в Django?

Я использую MySQL с движком InnoDB и уровнем изоляции REPEATABLE-READ.

Я написал функцию, которая, как мне кажется, должна атомически увеличивать IntegerField и давать мне значение после приращения. Мне хотелось бы узнать, уверен ли мой код в отношении проблем concurrency.

Мой код выглядит следующим образом:

class MyModel(models.Model):
  version = models.IntegerField()

  @staticmethod
  @transaction.commit_on_success
  def acquire_version(pk):
    MyModel.objects.filter(pk = pk).update(version = F('version') + 1)
    return MyModel.objects.get(pk = pk).version

Мое мышление заключается в том, что в двух одновременных вызовах UPDATE будут взаимно исключать друг друга из-за блокировки записи, а затем REPEATABLE-READ должны гарантировать, что мой следующий .get даст мне значение после UPDATE. Я прав?

(Это не общий вопрос "как я делаю атомный приращение?", уже есть один из них. Это вопрос о том, действительно ли этот конкретный способ.)

4b9b3361

Ответ 1

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

Таким образом, используйте диспетчер (object = MyManager()) и напишите SQL-запрос, который увеличивает номер версии (UPDATE mytable SET version=(version+1) WHERE pk=pk, см. здесь), и немедленно верните инкрементную версию экземпляра модели, прежде чем любой другой вызов будет выполнен.

См. также Managers