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

13

我正在使用InnoDB引擎和REPEATABLE-READ隔离级别的MySQL。

我编写了一个函数,我认为应该原子地递增IntegerField,并在增加后给我增加后的值。 我想知道是否有人能够提供意见,以确定我的代码是否能够很好地解决并发问题。

我的代码如下所示:

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之后的值。 我是正确的吗?

(这不是一个一般的“如何执行原子递增?”问题,已经有了一个这样的问题。这是关于这种特定方法是否有效的问题。)


你看过http://stdbrouw.github.com/django-locking/吗?我猜你是在做乐观锁定相关的工作。 - dstarh
相关内容:https://dev59.com/zHI-5IYBdhLWcg3w8dYQ - Ciro Santilli OurBigBook.com
1个回答

1

一个经验法则是:任何类型的自定义查询或自定义查询行为都应该放在manager方法中。 在你的情况下这很有道理,因为你可以在非常低的层级上递增、保存和返回版本号:在实际查询期间。

因此,使用Manager(object = MyManager())编写一个SQL查询来递增版本号(UPDATE mytable SET version=(version+1) WHERE pk=pk,参见这里),并在任何其他调用之前立即返回递增的模型实例版本。

另请参阅Managers


好的,但问题中给出的代码是正确的还是有误的? - kdt
我认为这更危险,因为.update()的实际实现可能是与Django版本无关的。而且你正在进行双重甚至三重查找。老实说,我不知道它现在是否正确。 - Remi

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接