0

想象一个相当复杂的 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) 类中转储数据。换句话说,如果代码中的某些内容获取数据,然后等待一段时间,然后将数据保存回来 - 那么只有最新的“保存程序”会保存其数据,所有其他(以前的)保存程序将丢失其更改。

这是一个“高负载”应用程序,数据库负载(我们使用 Postgres)非常高,我想避免任何会导致数据库活动或内存占用显着增加的事情。

另一个问题 - 我们附加了许多信号,甚至覆盖了 save() 方法,所以我想避免任何可能破坏信号或可能与自定义 save() 或 update() 方法不兼容的事情。

在这种情况下你会推荐什么?有什么特别的应用程序吗?交易?还要别的吗?

谢谢!

4

1 回答 1

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

如果这是一种可行的方法,则取决于您的长期任务到底是什么。用户可能仍会覆盖您保存在此处的数据。

于 2014-09-08T10:49:49.423 回答