Django Transactions,select_for_update,并发修改?
Django Transactions, select_for_update, concurrent modification?
我有一堆视图,我在执行之前检查某些条件是否为真。先执行哪个视图并不重要,但我担心一个用户使用一个视图,该视图在另一个视图中检查了条件后更改了数据。非常感谢对此的任何帮助。
我正在使用设置 ATOMIC_REQUESTS = True 的 2 勺建议,将每个请求包装在一个事务中。我的网站流量相对较低,所以我还不关心性能。也使用 postgres。
def feed_dog(self, dog_id):
dog = get_objects_or_404(Dog, pk=dog_id)
if not dog.removed and not dog.fed_today: # line 3
# do additional checks
dog.fed_today = True # line 5
dog.save()
# also modify other related objects
treat = Treats.objects.last()
treat.dogs_being_fed_with_this_treat.add(dog)
treat.save()
def remove_dog_from_feed_list(self, dog_id):
dog = get_objects_or_404(Dog, pk=dog_id)
if not dog.fed_today # line 12
dog.removed = True
dog.save()
treat.dogs_being_fed_with_this_treat.remove(dog)
treat.save()
所以我担心的是有人调用了feed_dog 视图,然后在检查第3 行之后但在第5 行开始之前,另一个用户调用了remove_dog 函数。由于当用户 2 调用 remove_dog 时 dog.fed_today 仍然为 False,第 12 行为 True,并且 remove_dog 视图继续并执行 dog.removed = True。同时 feed_dog 视图继续并设置 dog.fed_today=True,将狗添加到 treat 数组等。所以我有 dog.removed = True 的不一致状态,并且 dog.fed_today = 正确。
基本上我需要它,这样 Dog 模型上的某些属性不能同时为 True,例如 dog.fed_today =True 和 dog.removed=True。我也有这个相关的模型 Treat,我不希望狗对象已删除 = True 并且也位于 treat.dogs_being_fed 数组中。
问:这是一个合理的担忧吗?由于事务提供隔离,这是否意味着其中一个视图在另一个视图之前或之后访问数据(它们看不到半完成状态的数据)?
问:增加 Django/Postgres 与 Read Committed 的隔离度 属性 是否有帮助?
问:对 Dog 模型本身进行约束是否会有所帮助(比如使用 def clean 方法来说明 Dog 不能同时被移除 = True 和 fed_today = True?)。我主要是在查看视图中的内容。这会反映在交易中吗?我是否也可以创建一个约束来反映多个模型中的属性,比如不能有 dog.removed=True 并且让那只狗在 Treats.dogs_being_fed 数组中?
问:select_for_update 的目的是什么,对这里有帮助吗?如果事务已经应该提供隔离,那么 select_for_update 的目的是什么?
感谢任何帮助!
除非您了解数据库隔离级别,否则您真的无法有效地使用事务。如果您使用的是 PostgreSQL,请查看 their documentation on the subject.
回答您的具体问题:
这是一个有效的问题吗?
当然可以。默认的 READ COMMITTED
隔离级别不会保护数据库不受上面代码的影响。
由于事务提供了隔离,这是否意味着其中一个视图在另一个视图之前或之后访问数据(他们看不到半成品中的数据)状态)?
没有。不过,这大约就是 SERIALIZABLE
隔离级别的含义。
是否有助于增加 Django / Postgres 与 READ COMMITTED
的隔离 属性?
是的,但您通常不需要更严格的隔离级别,并且由于使用它们会降低性能,因此重新考虑您的数据库访问模式通常更有意义。
对 Dog
模型本身进行约束(例如使用 clean()
方法)是否有帮助?
没有。 Django 的验证方法应用于查询数据库后创建的 Python 对象。它们无助于防止竞争条件引起的数据损坏。 (不过,他们可能会在事后帮助检测它。)
如果事务本来就应该提供隔离,那么select_for_update()
的目的是什么?
select_for_update()
执行 SELECT
但会锁定匹配的行,以便它们不能在其他事务中同时修改。如前所述,这不是事务隔离级别的作用。
对这里有帮助吗?
是的!这是您问题的最简单解决方案,因为您选择(并且可以锁定)Dog
table 中的一行。如果两个函数都使用
dog = Dog.objects.filter(pk=dog_id).select_for_update().get()
然后他们都会尝试锁定有问题的行。如果有并发修改的尝试,第二个将等到第一个事务结束后再继续。
我有一堆视图,我在执行之前检查某些条件是否为真。先执行哪个视图并不重要,但我担心一个用户使用一个视图,该视图在另一个视图中检查了条件后更改了数据。非常感谢对此的任何帮助。
我正在使用设置 ATOMIC_REQUESTS = True 的 2 勺建议,将每个请求包装在一个事务中。我的网站流量相对较低,所以我还不关心性能。也使用 postgres。
def feed_dog(self, dog_id):
dog = get_objects_or_404(Dog, pk=dog_id)
if not dog.removed and not dog.fed_today: # line 3
# do additional checks
dog.fed_today = True # line 5
dog.save()
# also modify other related objects
treat = Treats.objects.last()
treat.dogs_being_fed_with_this_treat.add(dog)
treat.save()
def remove_dog_from_feed_list(self, dog_id):
dog = get_objects_or_404(Dog, pk=dog_id)
if not dog.fed_today # line 12
dog.removed = True
dog.save()
treat.dogs_being_fed_with_this_treat.remove(dog)
treat.save()
所以我担心的是有人调用了feed_dog 视图,然后在检查第3 行之后但在第5 行开始之前,另一个用户调用了remove_dog 函数。由于当用户 2 调用 remove_dog 时 dog.fed_today 仍然为 False,第 12 行为 True,并且 remove_dog 视图继续并执行 dog.removed = True。同时 feed_dog 视图继续并设置 dog.fed_today=True,将狗添加到 treat 数组等。所以我有 dog.removed = True 的不一致状态,并且 dog.fed_today = 正确。
基本上我需要它,这样 Dog 模型上的某些属性不能同时为 True,例如 dog.fed_today =True 和 dog.removed=True。我也有这个相关的模型 Treat,我不希望狗对象已删除 = True 并且也位于 treat.dogs_being_fed 数组中。
问:这是一个合理的担忧吗?由于事务提供隔离,这是否意味着其中一个视图在另一个视图之前或之后访问数据(它们看不到半完成状态的数据)?
问:增加 Django/Postgres 与 Read Committed 的隔离度 属性 是否有帮助?
问:对 Dog 模型本身进行约束是否会有所帮助(比如使用 def clean 方法来说明 Dog 不能同时被移除 = True 和 fed_today = True?)。我主要是在查看视图中的内容。这会反映在交易中吗?我是否也可以创建一个约束来反映多个模型中的属性,比如不能有 dog.removed=True 并且让那只狗在 Treats.dogs_being_fed 数组中?
问:select_for_update 的目的是什么,对这里有帮助吗?如果事务已经应该提供隔离,那么 select_for_update 的目的是什么?
感谢任何帮助!
除非您了解数据库隔离级别,否则您真的无法有效地使用事务。如果您使用的是 PostgreSQL,请查看 their documentation on the subject.
回答您的具体问题:
这是一个有效的问题吗?
当然可以。默认的 READ COMMITTED
隔离级别不会保护数据库不受上面代码的影响。
由于事务提供了隔离,这是否意味着其中一个视图在另一个视图之前或之后访问数据(他们看不到半成品中的数据)状态)?
没有。不过,这大约就是 SERIALIZABLE
隔离级别的含义。
是否有助于增加 Django / Postgres 与 READ COMMITTED
的隔离 属性?
是的,但您通常不需要更严格的隔离级别,并且由于使用它们会降低性能,因此重新考虑您的数据库访问模式通常更有意义。
对 Dog
模型本身进行约束(例如使用 clean()
方法)是否有帮助?
没有。 Django 的验证方法应用于查询数据库后创建的 Python 对象。它们无助于防止竞争条件引起的数据损坏。 (不过,他们可能会在事后帮助检测它。)
如果事务本来就应该提供隔离,那么select_for_update()
的目的是什么?
select_for_update()
执行 SELECT
但会锁定匹配的行,以便它们不能在其他事务中同时修改。如前所述,这不是事务隔离级别的作用。
对这里有帮助吗?
是的!这是您问题的最简单解决方案,因为您选择(并且可以锁定)Dog
table 中的一行。如果两个函数都使用
dog = Dog.objects.filter(pk=dog_id).select_for_update().get()
然后他们都会尝试锁定有问题的行。如果有并发修改的尝试,第二个将等到第一个事务结束后再继续。