Это безопасный способ увеличения и получения значения счетчика в 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. Я прав?
(Это не общий вопрос "как я делаю атомный приращение?", уже есть один из них. Это вопрос о том, действительно ли этот конкретный способ.)
Ответы
Ответ 1
Общее правило состоит в том, что любые пользовательские запросы или индивидуальное поведение запроса должны идти в методы менеджера.
Это имеет смысл в вашем случае, потому что вы можете увеличивать, сохранять и возвращать номер версии на очень низком уровне: во время фактического запроса.
Таким образом, используйте диспетчер (object = MyManager()
) и напишите SQL-запрос, который увеличивает номер версии (UPDATE mytable SET version=(version+1) WHERE pk=pk
, см. здесь), и немедленно верните инкрементную версию экземпляра модели, прежде чем любой другой вызов будет выполнен.
См. также Managers