web-dev-qa-db-ja.com

MySQLの「更新のために選択」動作

MySqlのドキュメントに従って、MySqlは複数の粒度のロック(MGL)をサポートしています。

ケース1

開いたターミナル-1:

// mysqlに接続されています

mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)

mysql> select id, status from tracking_number limit 5 for update;
+----+--------+
| id | status |
+----+--------+
|  1 |      0 |
|  2 |      0 |
|  3 |      0 |
|  4 |      0 |
|  5 |      0 |
+----+--------+
5 rows in set (0.00 sec)
mysql> 

開いたままにし、ターミナル2を開いた:

// mysqlに接続されています

mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)

mysql> select id, status from tracking_number limit 5 for update;

<!-- Hangs here. and after some time it says-->
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction

取得する行はたくさんありますが、T2はt1が完了するまで待機します。

ケース2

ターミナル1をそのまま残します。ターミナル2に移動します。

mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)

<!-- case 2.1 -->
mysql> select id, status from tracking_number where id=1;
+----+--------+
| id | status |
+----+--------+
|  1 |      0 |
+----+--------+
1 row in set (0.00 sec)

mysql> select id, status from tracking_number where id=2;
+----+--------+
| id | status |
+----+--------+
|  2 |      0 |
+----+--------+
1 row in set (0.00 sec)

<!-- case 2.2 -->
mysql> select * from tracking_number where id=2 for update;
<!-- Hangs here. and after some time -->
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
  1. しかし、なぜケース1で、T2はT1がロックしたのと同じ行のセットを待つのですか?

  2. これは、制限のない選択クエリ(limintパラメーターを使用した場合でも、別の範囲でも試した)がテーブル全体をブロックすることを意味しますか?

  3. レコードのフィールドを指定せずにトランザクションを独立してロックする方法はありますか(つまり、where field = valueを使用せずに)?
  4. 一般的に(またはJava同時ロック)のように、書き込みロックは排他的で読み取りはそうではありません。2.1の場合、レコードは書き込みロックモードですが、T2は同じレコードをどのように読み取ることができますか?これは許可されていますそれをロックすることのポイントは何ですか?
  5. ケース2.2は理解されています。

端末とトランザクションを開きました:

mysql> update tracking_number set status=4 where status=0 limit 5;
Query OK, 5 rows affected (0.00 sec)
Rows matched: 5  Changed: 5  Warnings: 0

それをそこに残して、別のターミナルとトランザクションを開きました:

mysql> update tracking_number set status=5 where status=0 limit 5; 

T1をコミット(またはロールバック)するまで、T2は成功しませんでした。

  1. この動作はなぜですか?
28
Pragalathan M

これらのロックの仕組みを説明します。

1ケース

T1がテストテーブルの一部の行を更新しようとしています。このトランザクションは、すべてのテーブルにIXロックを配置し、最初の5行にXロックを配置します。

T2がテストテーブルの一部の行を更新しようとしています。このトランザクションは、すべてのテーブルにIX(IXはIXと互換性があるため)ロックをかけ、最初の5行を試みますが、XはXと互換性がないため実行できません。

だから私たちは元気です。

2.1ケース

T1がテストテーブルの一部の行を更新しようとしています。このトランザクションは、すべてのテーブルにIXロックを配置し、最初の5行にXロックを配置します。

T2は、テストテーブルからいくつかの行を選択しようとしています。そして、それはロックを配置しません(InnoDBが非ロック読み取りを提供するため)

2.1ケース

T1がテストテーブルの一部の行を更新しようとしています。このトランザクションは、すべてのテーブルにIXロックを配置し、最初の5行にXロックを配置します。

T2は、テストテーブルの一部の行を更新(更新用に選択)しようとしています。テーブル全体にISを配置し、行にSロックを取得しようとしますが、XとSに互換性がないため失敗します。


また、常に分離レベルに注意してください。レベルが異なると、ロックを解放/獲得するメカニズムが異なります。

それが役に立てば幸い

23
ravnur