これまでにMySQLトランザクションを使用したことはありません。何かを明確にしたいだけです。
2人のユーザーが非常に正確な時間にクエリを実行した場合、MySQLはこれをどのように処理しますか?例えばユーザーがレコードを更新しようとしています。
user1:テーブルセットの更新column = column-4 where column_id = 1;
user2:テーブルセットを更新しますcolumn = column-7 where column_id = 1;
トランザクションを使用する場合、MySQLは最初に実行されるクエリを選択し、最初のクエリがコミットされるまで2番目のユーザーをロックしますか?それはテーブルロックですか、それとも行ロックですか?
3番目のユーザーがselectステートメントを発行するとどうなりますか? MySQLが返す値は何ですか?
追伸これはInnodbにあります。
このような単一のステートメントは、トランザクションまたは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つの接続がsameの順序で複数のものを取得する場合、一方が他方が完了するまで遅延させることができます。これが「永久に待機する」のを防ぐために、デフォルトの50秒innodb_lock_wait_timeout
。単純なUPDATEs
のペアは、実際にはこのケースの例です。すぐに終わります。もう1つは、最初のものが終了するまで停止します。
触れたものを一貫して順序付けすることで、デッドロックを(場合によっては)遅延に変換できることに注意してください。
autocommit = 1:BEGIN
を呼び出さずにこの設定およびを使用すると、各ステートメントは事実上次のようになります。
BEGIN;
your statement
COMMIT;
autocommit = 0:これは、発生するのを待つのに問題です。書き込みクエリを実行すると、BEGIN
が暗黙的に生成されます。ただし、最終的にCOMMIT
を発行するのはユーザーの責任です。そうしないと、なぜシステムがハングするのか不思議に思うでしょう。 (もう1つの一般的な初心者向けのバグ。)私のアドバイス:「=0
"。