想象一下具有前端和后端部分的相当复杂的Django应用程序。一些用户修改前端部分的一些数据。有些脚本会在后端部分定期修改相同的数据。
示例:
instance = SomeModel.objects.get(...)
# (long-running part where various fields are changed, takes from 3 to 20 seconds)
instance.field = 123
instance.another_field = 'abc'
instance.save()
如果某个人(或某个东西)在该部分更改某些字段时更改了实例,那么更改将会丢失,因为最近将保存实例,从Python(Django)类转储数据。换句话说,如果代码中的某些内容需要数据,然后等待一段时间,然后将数据保存回来 - 那么只有最新的“保护程序”将保存其数据,所有其他(之前的)数据将丢失其更改。 / p>
这是一个“高负载”应用程序,数据库负载(我们使用Postgres)非常高,我想避免任何会导致DB活动或内存大量增加的内容。
另一个问题 - 我们附加了许多信号,甚至覆盖了save()方法,因此我想避免任何可能破坏信号或可能与自定义save()或update()方法不兼容的内容。< / p>
在这种情况下你会推荐什么?有什么特别的应用吗?交易?还有什么吗?
谢谢!
答案 0 :(得分:2)
防止这种情况的正确方法是使用select_for_update
确保数据在读取和写入之间不会发生变化。但是,这会导致行被锁定以进行更新,因此这可能会显着降低应用程序的速度。
Oen解决方案可能是读取数据并执行长时间运行的任务。然后在保存之前启动事务,再次读取数据,但现在使用select_for_update
并验证原始数据是否未更改。如果数据仍然相同,则保存。如果数据已更改,则中止并重新运行长时间运行的任务。这样你就可以尽可能地保持锁定。
类似的东西:
success = False
while not success:
instance1 = SomeModel.objects.get(...)
# (long-running part)
with django.db.transaction.atomic():
instance2 = SomeModel.objects.select_for_update().get(...)
# (compare relevant data from instance1 vs instance2)
if unchanged:
# (make the changes on instance2)
instance2.field = 123
instance2.another_field = 'abc'
instance2.save()
success = True
如果这是一种可行的方法,那取决于您长期运行的任务究竟是什么。并且用户可能仍会覆盖您在此处保存的数据。