在Django中递增并获取计数器值的方式安全吗?
我正在使用MySQL数据库,选择了InnoDB引擎和REPEATABLE-READ隔离级别。
我写了一个函数,想让它能够安全地把一个整数字段加1,并且在加完之后能给我这个新值。我想听听大家对我的代码在处理并发问题时是否可靠的看法。
我的代码大致是这样的:
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
我的想法是,如果有两个同时进行的调用,更新操作会因为写锁而互相排斥,然后REPEATABLE-READ应该能保证我后续的.get操作能拿到更新后的值。我这样理解对吗?
(这不是一个关于“我该如何做原子加法?”的普遍问题,已经有类似的问题了。这是关于我这种特定方式是否有效。)
1 个回答
1
一个简单的经验法则是,任何自定义查询或者特别的查询行为都应该放在管理器的方法里。这样做在你的情况下是合理的,因为你可以在非常基础的层面上进行版本号的递增、保存和返回:也就是在实际查询的时候。
所以,使用一个管理器(object = MyManager()
),然后写一个SQL查询来递增版本号(UPDATE mytable SET version=(version+1) WHERE pk=pk
,具体可以参考这里),并且在任何其他操作执行之前,立即返回递增后的模型实例的版本。
你还可以查看管理器的相关内容。