2

ブログプラットフォームには、「更新された」日時フィールドを含む「記事」モデルがあります。

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

訪問者が24時間以内に初めて記事を開いたとき、さまざまなモデルフィールドで時間のかかる計算を行い、その後モデルをデータベースに保存します。これにより、「updated」フィールドも現在のdatetime.now()に更新されます。

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

記事がほぼ同時にリクエストされた場合、最初のリクエストでの時間のかかる操作はまだ終了していないため、同じオブジェクトで1日1回の操作が再開されます(article.updatedには古い値が残っています)。計算を開始する直前にarticle.save()を追加で呼び出すのに役立ちますか?または、このデータはデータベースへの保存からリクエストが完了するまで延期されましたか?

4

3 に答える 3

2

データベースで行レベルのロックを行うDjango1.4で導入されたクエリセットselect_for_updateを使用します。一致したすべてのエントリは、トランザクションブロックが終了するまでロックされます。つまり、他のトランザクションがそれらのロックを変更または取得することはできなくなります。datgabaseバックエンドに固有の落とし穴がいくつかあるので、完全に信頼する前に、必ず読んでテストしてください。

実装とは無関係にそれを行う他のいくつかの方法は、lockedブール属性を持つようにモデルをカスタマイズすることです。あまりきれいではありませんが、実行可能なソリューションです。Djangoでオブジェクトをロックする最も簡単な方法は何ですかを参照してください

于 2012-09-21T14:27:43.583 に答える
2

いくつかの提案:

  • 時間のかかる計算を要求/応答サイクルからバックグラウンドに移行することをお勧めします。ここではメッセージキューを使用できます(人気のあるセロリのように)。これが最善の解決策だと思いますが、単純なタスクではやり過ぎになる可能性のある追加の管理が必要になる場合があります。
  • キャッシュを使用する場合は、オブジェクトがロックされているというフラグを設定できます。キャッシュがさまざまなインタープリター(memcachedなど)に共通している場合は、アプリを実行するPythonインタープリターが多数ある場合でも機能します。
  • 更新手順をスケジュールして(cronおよびカスタムDjango管理コマンドを使用)、24時間以上前に更新されたすべてのオブジェクトを更新できます。大量のオブジェクトとかなりの処理時間がない限り、機能します。
于 2012-09-22T10:17:34.107 に答える
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()db行(ID article_IDの記事)をロックします。行はトランザクションの終了時にロック解除されますが、はでupdate_article()ラップされているため、関数の終了時にロックが解除され@transaction.commit_on_successます。

PS:Django1.4以降で利用可能

于 2013-04-15T16:54:43.183 に答える