web-dev-qa-db-ja.com

MySQL:トランザクションは行をロックしますか?

これまでに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にあります。

13
zer09

このような単一のステートメントは、トランザクションまたは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 "。

17
Rick James