2

对于我们的博客平台,我们有一个“文章”模型,其中包含一个“更新的”日期时间字段:

class Article(models.Model):
    updated = models.DateTimeField(null=True, blank=True)
    ...

当一篇文章在 24 小时内第一次被访问者打开时,我们会对不同的模型字段进行一些耗时的计算,然后将模型保存到数据库中。有了这个,我们还将我们的“更新”字段更新为当前的 datetime.now()。

if (datetime.now() - article.updated).days > 1:
    # do some time consuming calculations
    article.updated = datetime.now()
    article.save()

当一篇文章或多或少同时被请求时,第一次请求的耗时操作尚未完成,导致每天一次的操作在同一个对象上再次开始(article.updated 仍然具有旧值)。在开始计算之前另外调用 article.save() 是否有帮助?还是将这些数据从保存到数据库中推迟到请求完成?

4

3 回答 3

2

一些建议:

  • 最好将耗时的计算从请求-响应周期转移到后台。这里可以使用消息队列(如流行的celery)。我认为这是最好的解决方案,但它可能需要一些额外的管理,这对于简单的任务来说可能是多余的;
  • 如果你使用缓存,你可以设置一个标志对象被锁定。如果缓存对于不同的解释器(如 memcached)是通用的,那么即使您有许多运行您的应用程序的 Python 解释器,它也可以工作;
  • 您可以安排更新过程(使用 cron 和自定义 Django 管理命令)来更新 > 24 小时前更新的所有对象。除非你有大量的对象和相当长的处理时间,否则它会起作用。
于 2012-09-22T10:17:34.107 回答
2

使用Django 1.4 中引入的查询集select_for_update ,它在数据库中进行行级锁定。所有匹配的条目都将被锁定,直到事务块结束,这意味着其他事务将被阻止更改或获取对它们的锁定。有一些特定于 datgabase 后端的陷阱,因此请确保在完全依赖它之前阅读并测试它。

其他一些独立于实现的方法是通过自定义模型以具有locked布尔属性。不是很整洁,但一个可行的解决方案。请参阅在 Django 中锁定对象的最简单方法是什么

于 2012-09-21T14:27:43.583 回答
2

精简版:

@transaction.commit_on_success
def update_article( article_id ):
    article = Article.objects.select_for_update().get( pk = article_id )
    if (datetime.now() - article.updated).days > 1:
        # do some time consuming calculations
        article.updated = datetime.now()
        article.save()

select_for_update()锁定数据库行(ID 为 article_ID 的文章)。update_article()该行在事务结束时解锁,因为它被包裹在函数的末尾@transaction.commit_on_success

Ps:从 Django 1.4 开始可用

于 2013-04-15T16:54:43.183 回答