在Django中递增并获取计数器值的方式安全吗?

13 投票
1 回答
796 浏览
提问于 2025-04-17 00:06

我正在使用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,具体可以参考这里),并且在任何其他操作执行之前,立即返回递增后的模型实例的版本。

你还可以查看管理器的相关内容。

撰写回答