ロック
行レベルのロック
select_for_update(NOWAIT =偽、偽= skip_locked)#の注目は、トランザクションを開く方法のように、我々は次のトランザクション参照、トランザクション内で使用する必要があります。
クエリは、SELECT ... FOR UPDATE文を生成します、データベースのサポート場合は、トランザクションの終わりまでロックされた行のセットを返します。
例えば:
クエリが共有ロックであるので、我々は、手動でミューテックスを追加することができたときのMySQLを自動的に追加するので= Entry.objects.select_for_update()。フィルタ(著者=からrequest.user)#エントリは、ミューテックスを追加します。、、、更新プログラムを作成する際の動作を削除するMySQLの自動行レベルミューテックス
すべての一致する行は、トランザクションの終わりまでロックされています。これは、データが変更、他のトランザクションを防ぐためにロックすることができることを意味しています。
ロックが解除されるまで、通常の状況下では、ロックされた行に関連するその他の事項場合は、このクエリがブロックされます。あなたはこの問い合わせはブロックしたくない場合は、(NOWAIT =真)select_for_updateを使用しています。他のトランザクションが競合ロック、ミューテックスを保持している場合、クエリは例外DatabaseErrorをスローします。また、ロックされた行を無視します(=真をskip_locked)select_for_updateを使用することができます。原因とValueErrorを設定しながらNOWAITとskip_lockedは、相互に排他的です。
現在、PostgreSQLの、OracleとMySQLデータベースバックエンドサポートselect_for_update()。しかし、MySQLはNOWAITとskip_lockedパラメータをサポートしていません。
これらのオプションを使用する(MySQLなど)データベースのバックエンドをサポートされていない真= NOWAITまたはTrueが(select_for_updateに変換= skip_locked)予期せず終了からコードを防止することができるDatabaseError例外になります。
表ロック(理解)
LockingManagerクラス(models.Manager): 。「」「Managerへこのページの追加/ UNLOCK機能をロックするには、 例:: 仕事(models.Model)クラス:実際には#が、そうロードされていないが、ORMで直接テーブルを作成し、このロックテーブルの定義を与えます外層LckingManagerことなく、それをロック解除(model.Manager)クラスジャンゴロックテーブルSQL文ネイティブおよびネイティブSQL文を送信するために接続モジュールによって提供される方法を、アンロック マネージャ= LockingManager() カウンタ= models.IntegerField (ヌル= Trueの場合、デフォルト= 0)が @staticmethod DEF(JOB_ID)をdo_atomic_update 「」「アップデート仕事整数は、5未満にITを維持する」「」 試してみてください 。#の一つは、唯一のHTTPリクエストを一度この更新することができませんことを確認し Job.objects.lockは、 () 仕事= Job.object.get(ID = JOB_ID) #私たちはテーブルをロックしていない場合は2 simultanous #要求がカウンター増えることがあります両方の 5の上に行く# 5 <job.counter場合: job.counter + = 1 job.saveを() 最後に: Job.objects.unlock() "" " デフロック(自己 ):"""ロックテーブル。 アトミック更新が可能となるようにオブジェクト・モデル・テーブルをロック。 Simulatenousデータベースアクセス要求保留ロックはロック解除() '編になるまで。 注:複数のテーブルをロックする必要がある場合は、あなたがそれらロック行う必要がある 1つのSQL句ですべてを、この機能は十分ではありません。避けるために 死んでロックを、すべてのテーブルは、同じ順序でロックする必要があります。 http://dev.mysql.com/doc/refman/5.0/en/lock-tables.htmlを参照して "" " カーソル= connection.cursor() 表= self.model._meta.db_table logger.debug("ロック・テーブル%S "%テーブル) cursor.execute( "LOCKテーブル%S WRITE" %テーブル) ロー= cursor.fetchone() 戻り行 DEF(自己)をアンロック :"""テーブルのロックを解除します。「」」 カーソル=接続。 行= cursor.fetchone() 戻り行
MySQLのトランザクションについて、mysqlのブログは、私はそれが非常に明確にしている、とあなたが取引を行う場合Djangoはある時、我々は見てみましょう。そこ関数デコレータ、その上の(グローバル)との形でコンテキストマネージャの形で、ミドルウェアの形で、django1.8バージョンの前にトランザクションを追加するためのさまざまな方法がありますが、メソッドの多くは、バージョン1.8を更新するためにした後、以下の我々は、最新のを言います:
グローバル・オープン1
トランザクションにおける各リクエストをラップされたWebアプリケーションでは、一般にトランザクション処理モードで使用されています。この機能は、使用することは非常に簡単です、あなただけのTrueに設定されたエントリーATOMIC_REQUESTSを設定する必要があります。
それはこのように動作します:リクエストが来たとき、Djangoはビューのメソッドを呼び出す前に、トランザクションを開きます。リクエストが適切に準備し、正しく結果を返した場合、Djangoはトランザクションをコミットします。そうでなければ、Djangoはトランザクションをロールバックします。
= {DATABASES 'デフォルト':{ 'ENGINE': 'django.db.backends.mysql'、 'NAME': 'mxshop'、 'ホスト': '127.0.0.1'、 'PORT': '3306'、 「USER ':'ルート' 'PASSWORD ':' 123'、 ' OPTIONS ':{ "init_command": "= SETのdefault_storage_engine' 'INNODB" # はinit_command' ':「SET sql_modeの=' STRICT_TRANS_TABLES ' "、オープン#1を設定厳密SQLモード } 「ATOMIC_REQUESTS」:真、#グローバル情勢を有効にし、プロセス全体httpリクエストの応答にバインドされている
「自動コミット」:偽、#グローバルは自動送信、注意をキャンセル }、
"OTHER '{
' ENGINE ':' django.db.backends.mysql」は、
......
}#はまた、他のデータベースを構成することができ
}
すべての統一されたSQLのHTTP要求は、対応するトランザクションの実行(すべて成功、または他のすべてが失敗するかのいずれか)に配置されている上に、このアプローチがあります。あなたはhttpリクエストのために水をオンにする(その後、トランザクションをカスタマイズ)したい場合は、あなたがnon_atomic_requestsデコレータを使用することができ、グローバルコンフィギュレーションされ、その後、彼は業務を制御することはできません
django.db輸入取引から transaction.non_atomic_requests @ デフmy_view(リクエスト): do_stuff() transaction.non_atomic_requests(= 'その他'を使用して)@ デフmy_other_view(リクエスト): do_stuff_on_the_other_database()
しかし、Djangoのドキュメントはお勧めしません、と言います。HTTPリクエストとの取引が一緒にバインドする場合はそのため、ビューは、データベースのロック競合現状へのアプリケーションとデータベースのクエリの効率に依存しています。流量アップ、パフォーマンスが影響を受ける場合は、あなたが行うことを知って
ですからを通じて、この方法をお勧めします以下 transaction.atomic
、より明示的に制御取引に。私たちは、アトミック・ブロック、実行されると、データベースレベルで保証原子を提供できます。コードブロックが正常に終了した場合、対応する変更をデータベースに提出されるCOMMIT;例外は、実行中に遭遇した場合、それはコード・セグメントに応じてすべての変更をロールバックします。
2つの局所業務
アトミック(使用して=なし、そのセーブポイント=真)[ソース]、パラメータ:使用して=「他の」、あなたは他のと同様に、デフォルトに加えて、このトランザクションを有効にするには、我々は上記のデータベースの構成を見て、他のデータベースを操作するときには、ありますデフォルトはデフォルトです。セーブポイントのオープン・トランザクションを意味セーブポイント、私は見てお勧めのデータベースブログのセーブポイントの説明の内部の業務セグメントを。
原子性は、プロパティデータベースのトランザクションです。私たちは、原子含むコードのブロックを作成することができ、アトミック使用します。ブロック通常動作が完了すると、すべての変更がデータベースにコミットしています。例外がある場合は逆に、変更はロールバックされます。
アトミック・ブロックを管理することもコード方法に埋め込まれてもよいです。外部コードブロックは例外をスローこの場合も内部コードブロック通常動作場合、それは、データベースへの変更を送信する方法はありません。
使用方法1:機能を使用するデコレータを行うには
django.db輸入取引から transaction.atomic @ デフviewfunc(リクエスト): #このコードは、トランザクション内で実行されます。 do_stuff()
シンタックス2:セットポイント事務を保存し、実際には、コンテキストマネージャとして使用します
django.db輸入取引から デフviewfunc(リクエスト): #このコードは、自動コミットモード(Djangoのデフォルト)で実行されます。 do_stuff() transaction.atomicと():#保存点 #このコードはトランザクション内で実行されます。 do_more_stuff() do_other_stuff()
試しに/を除くアトミックブロックたら、自然の整合性エラーは、次の例のような、処分されます。
django.db輸入IntegrityError、トランザクションから transaction.atomic @ :デフviewfunc(リクエスト) create_parent() してみてください: transaction.atomicで(): generate_relationships() IntegrityError除く: handle_exceptionは() add_children()
用法3:また、トランザクションのトランザクションコンテキストマネージャ機能、トランザクションコンテキストマネージャネストされたトランザクションコンテキストマネージャ等をネスト、ネストされてもよいです。以下のネストされた関数のコンテキストの例は以下のとおりです。
インポートIntegrityErrorのdjango.db、トランザクション transaction.atomic @ DEF viewfunc(要求): create_parent() してみてください。 transaction.atomic()を持つ: generate_relationships()
#other_task()#はも注意してください、あなたは内部取引で書く場合あなたはタスクがトランザクションを見るために提出する前に、データ、またはデータ内の上記データテーブルを変更することで照会すると、他の操作は、これらの操作だけで完了した後、トランザクションがコミットされます、それは、と言うことです。 :除くIntegrityError handle_exceptionは() )(add_children
この場合、データの整合性制約を破るために、たとえgenerate_relationships()のコード、あなたはまだ)(add_childrenでデータベース操作を実行することができ、および(create_parentを変更)生産も有効です。generate_relationshipsに安全にロールバックされていた)(変更、()を呼び出す前にhandle_exceptionはあることに注意してください。必要に応じて、そのため、あなたはまだ例外ハンドラでデータベースを操作することができます。
コードのアトミック・ブロック内の例外をキャッチしないようにしよう アトミックブロックコードが実行を終了したときに、Djangoは、コミットまたはロールバックに対応するコードの通常の操作に応じて実行されるからです。キャッチとは、内部例外アトミックブロックを処理した場合、エラーコード自体がそこに隠さすることができるので、いくつかの予期しない不愉快なことが起こる可能性があります。 そしてDatabaseErrorで濃縮して、そのサブクラス(例えばIntegrityError)を恐れています。これは本当に例外で発生した場合、トランザクションは破棄され、Djangoは、コードの実行後に操作をロールバックします。あなたがロールバックする前に、いくつかのデータベース操作を実行しようとすると、DjangoはTransactionManagementErrorをスローします。例外はあなたが関連ORMで通常信号プロセッサを考えスローされ、この動作が発生しました。 正しくアトミック・ブロックの上に示された例外をキャッチします。必要な場合は、トランザクションのネストである、それを行うには、コードの追加アトミックブロックを追加します。これの利点は次のとおりです。例外が発生したとき、それは明らかにあなたがそれらの操作をロールバックする必要が伝えることができ、そしてそれらは必要ありません。
アトミック性を確保するためには、原子はまた、いくつかのAPIを禁止しました。トランザクションをロールバック、コミットしようとしている、と自動的にこれらの操作のデータベース接続の状態に提出変化と同じように、コードのアトミック・ブロックは、それ以外の場合は、例外がスローされます、約束ではありません。
ここではDjangoのトランザクション管理コードは次のとおりです。
- トランザクションを開くと、一番外側のアトミックブロックに入ります。
- 内部へのセーブポイントアトミックブロックアクセスを作成します。
- あなたは内部の原子の放出が終了するか、トランザクションをロールバックするとき、そこにネストされている場合は、トランザクションの内側の層が提出されていない、注意を払うことは、リリース(正常終了)またはロールバックします
- トランザクションがコミットまたは最も外側のアトミックブロック出口をロールバックすると、
あなたはポイントのパラメータがセーブポイントを作成するために、内部のコードブロックを無効にするにはFalseに設定されて保存することができます。例外が発生した場合、Djangoはブロックを出た後に実行されたときに最初の親ロールバック、存在する場合、それ以外の場合は、コードの最も外側のブロックにロールバックされ、バックポイントにロールバックされます。この位置を保存し、ポイントを保存します。トランザクションの外側の層は、まだアトミック性を保証することができます。ただし、このオプションは、時間の大きなポイントのオーバーヘッドを保存するために使用されるべきです。結局のところ、それは欠点があります。上記のエラー処理メカニズムを破壊します。
注意:トランザクションのみトランザクション管理のためのデータベース層の操作のために、それは、トランザクション管理のPythonの操作として理解することはできません
example_view DEF(要求): 偽タグ= transaction.atomicと(): タグ= Trueの change_obj()#オブジェクト変数変更 obj.saveを() DataErrorレイズ 印刷( "タグ="タグ)#結果が真である、それは言うことですトランザクションがロールバックされ、この割り当てが成功した場合でも、トランザクション内のpython変数の割り当て、
また、注意してください:あなたが世界情勢、地域の情勢を設定し、それが競合する可能性がある場合、他の問題に加えて、SQL内部関数が、それはありません。このコンテキスト管理では、ある場合にトランザクションが完了した後、あなたの地元のことがありますパッケージの範囲内で局所的な業務内の他のSQL関数が問題だグローバルロールは関係するすべてのSQL要求と応答をバックアップするので、それが後に推奨されますので、お近くの取引は、提出されていません現地情勢を乗り切るために、グローバルな業務を構成するために投影しないようにしよう、もちろん、あなたのビジネスシナリオを見てください。
トランザクションの他の方法
transaction.atomic @ DEF viewfunc(要求): a.save() #オープン取引a.saveは現在含まれています() SID = transaction.savepoint()#は、セーブポイントの作成 b.save() になりました(a.saveが含まれています#オープントランザクションを)とb.save() want_to_keep_b IF: transaction.savepoint_commit(SID)ポイント#の節約するために提出 )(静止画(含まれていa.save#オープントランザクション)とb.save :他の ポイント節約するためにtransaction.savepoint_rollback(SID)#ロールバックを #をオープン()のみa.saveトランザクションは現在含ま transaction.commit()#マニュアルがトランザクションをコミットすると、デフォルトが自動的に設定されていない場合は自動的に自動コミット設定した場合、これらの言葉を書いていない、提出取り消すことを、提出され= Falseのは、手動で提出する必要があります。
トランザクションの分離を確実にするために、我々はまた、上記のロックが達成されて組み合わせることができ、それは、クエリ内の問題に言うことです、我々はアイソレーションを確保するための手段をロックselect_for_updateディスプレイを使用し、ロックには、例えば、トランザクションの終了後にリリースされます、理解:()
@ transaction.atomic ##簡単に開いているトランザクションは、 DEF(セルフ)を扱う: ##ユーザーが存在するかどうかのテスト を試して: ##トランザクションが終了するまでロックが行を照会 ユーザー= User.objects.select_for_updateは、()(open_id = self.user GET。 .open_id) #other SQLステートメント を除くUser.DoesNotExist: 昇給BaseError(-1、 'ユーザーが存在しないわけではありません。')
Djangoの外部Pythonスクリプトによってトランザクションをテストするには:
輸入OS __name__ == '__main__'の場合: os.environ.setdefault( "DJANGO_SETTINGS_MODULE"、 "BMS.settings") 輸入ジャンゴ django.setup() 輸入日時 app01輸入モデルからは、 試してみてください。 django.db輸入取引から 取引に。アトミック(): new_publisher = models.Publisher.objects.create(名= "火星出版社") models.Book.objects.create(タイトル= "橘子物语"、公開日= datetime.date.today()、PUBLISHER_ID = 10 )#指定一个不存在的出版社ID Eなどの例外を除いて: 印刷(STR(e)参照)
いくつかは、以下の原則が、それは少し重要設定と言います:
1.トランザクション短い保持
2.避けトランザクションROLLBACK
3.セーブポイントが回避
4.デフォルトでは、悲観的ロックに応じて
ロック楽観的トランザクション・スループットの考慮事項厳しい5.
表示transaction文開い
行7.ロックできるだけ短く、より良い、ロック時間