このような単一のステートメントは、トランザクションまたはautocommit = ONを使用して、MyISAMまたはInnoDBと同じように機能します。クエリを実行するのに十分なだけブロックされるため、他の接続がブロックされます。完了すると、他の接続が続行されます。すべての場合において、列はすぐに11減少します。
3番目のユーザーは、0、4、7、11のいずれかで値が減少する場合があります。「非常に正確な時間」は、各ステートメントの実行のある時点で、シングルスレッドロックがチェック/設定/何でもチェックされるため、実際には不可能です。それは、彼らがされますちょうど非常に速くあなたがそれを見ることができない、シリアル化されます。
InnoDBはテーブルではなく、行のみをロックします。(OK、DDLステートメントはより大胆なロックを行います。)
さらに興味深いのは、2つのことを変更するトランザクション、または顕著な時間を要するトランザクションです。
インテンションケース:単一のアイテムですが時間がかかります:
BEGIN;
SELECT something;
think about it for a while
UPDATE that something;
COMMIT;
selectは次のように記述する必要があります。
SELECT something FOR UPDATE;
これは他の接続に「行を更新するつもりです。ごちゃごちゃにしないでください」と伝えます。(多くの初心者がこの繊細さを見逃しているため、この例を取り上げます。)
デッドロックケース: 2つのことで混乱させる:
BEGIN; -- in one connection
UPDATE thing_1;
UPDATE thing_2;
COMMIT;
BEGIN; -- in another connection, at the "exact same time"
UPDATE thing_2;
UPDATE thing_1;
COMMIT;
これは、デッドロックの典型的な例です。それぞれが1つのものを取得してから、もう1つのものに到達します。明らかにそれを機能させることはできません。1つのトランザクションが強制終了されます。他は完了する。したがって、あなたがしなければならない、あなたがそれを発見することができますので、エラーをチェック。
デッドロックに対する通常の反応は、失敗したトランザクション全体を再生することです。その時までに、他の接続は干渉せず、問題なく続行するはずです。(OK、さらに別の接続が別のデッドロックを作成する可能性があります。)
遅延のケース: 2つの接続が同じ順序で複数のものを取得する場合、一方が完了するまで一方を遅延させることができます。これが「永久に待機する」のを防ぐために、デフォルトの50秒がありますinnodb_lock_wait_timeout
。シンプルなペアUPDATEs
は、実際にはこのケースの例です。すぐに終わります。もう1つは、最初のものが終了するまで停止します。
触れたものを一貫して順序付けることで、デッドロックを(場合によっては)遅延に変換する方法に注意してください。
autocommit = 1: この設定を使用するとBEGIN
、を呼び出さなくても、各ステートメントは事実上次のようになります。
BEGIN;
your statement
COMMIT;
autocommit = 0: これは、発生するのを待つのに問題があります。書き込みクエリを実行すると、a BEGIN
が暗黙的に生成されます。ただし、最終的に発行するのはあなたの責任COMMIT
です。そうしないと、なぜシステムがハングするのか不思議に思うでしょう。(もう1つの一般的な初心者向けバグ。)私のアドバイス:「使用しない=0
」。