web-dev-qa-db-ja.com

「transaction.atomic」は「transaction.commit_on_success」と同じですか?

Django 1.6は、1.5からのトランザクション管理のリホールの一部として@transaction.atomicを提案しています。

私はDjango管理コマンドによって呼び出される関数を持っています。このコマンドはcronによって呼び出されます。つまり、この場合、トランザクションをトリガーするHTTP要求はありません。スニペット:

from Django.db import transaction

@transaction.commit_on_success
def my_function():
    # code here

上記のコードブロックでは、 commit_on_successmy_functionで行われたすべての作業に単一のトランザクションを使用します。

@transaction.commit_on_success@transaction.atomicに置き換えると、同じ動作になりますか? @transaction.atomicドキュメントの状態

アトミック性は、データベーストランザクションの定義プロパティです。 atomicを使用すると、データベースの原子性が保証されるコードブロックを作成できます。コードブロックが正常に完了すると、変更がデータベースにコミットされます。例外がある場合、変更はロールバックされます。

それらが同じ振る舞いをもたらすと思います。正しい?

61

はい。以前にcommit_on_successを使用した場所でatomicを使用する必要があります。

ただし、新しいトランザクションシステムはより堅牢で一貫性があるように設計されているため、異なる動作が見られる可能性があります。たとえば、データベースエラーをキャッチして続行しようとすると、TransactionManagementErrorが表示されますが、以前の動作は未定義で、おそらくケースに依存していました。

ただし、適切に作業を行っている場合は、すべてが同じように機能し続ける必要があります。

このテーマについて読んだドキュメントに基づいて、これらのデコレータがネストされている場合には大きな違いがあります。

2つのatomicブロックのネストは、2つのcommit_on_successブロックのネストと同じようには機能しません。

問題は、これらのブロックから得たい2つの保証があることです。

  • ブロック内のすべてがコミットされるか、何もコミットされないかのいずれかで、ブロックのコンテンツをアトミックにする必要があります。
  • 例外なくブロックを離れると、ブロック内に書き込んだすべてが永続的であることが保証されます。

ブロックがネストされている場合、両方の保証を提供することは不可能です。最も内側のブロックを出た後、最も外側のブロックを出る前に例外が発生した場合、次の2つの方法のいずれかで失敗する必要があります。

  • 最も内側のブロックに耐久性を提供しない。
  • 最も外側のブロックに原子性を提供できません。

ここに違いがあります。 commit_on_successを使用すると、最も内側のブロックに耐久性が与えられますが、最も外側のブロックには原子性がありません。 atomicを使用すると、最も外側のブロックに原子性が与えられますが、最も内側のブロックには耐久性がありません。

ネストの場合に単純に例外を発生させると、問題が発生するのを防ぐことができます。一番内側のブロックは常に例外を発生させるため、永続性は保証されません。しかし、これはある程度の柔軟性を失います。

より良い解決策は、あなたが求めているものについてより細かくすることです。原子性と耐久性を個別に要求できる場合は、ネストを実行できます。耐久性を要求するすべてのブロックが、原子性を要求するブロックの外側にあることを確認する必要があります。ブロック内で原子性を要求する永続性を要求するには、例外を発生させる必要があります。

atomicは原子性部分を提供することになっています。 Django 1.6.1には耐久性を要求できるデコレータがありません。コードレビューで posted を書きました。

61
kasperd