8

InnoDB を使用して MySQL にテーブルがあり、コミットされていない読み取りのトランザクション分離レベルを使用しています。@x示されているように設定するとロックが取得されるのはなぜですか?

mysql> set @x = (select userID from users limit 1);
Query OK, 0 rows affected (0.02 sec)

mysql>

別のプロンプトからこのテーブルを更新しようとすると、タイムアウト エラーが発生します。

mysql> update users set userID = 1;
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
4

2 に答える 2

2

価値のあることとして、このロックは次のことに限定されませんREAD-UNCOMMITTED

mysql1> show variables like '%isolation%';
+---------------+-----------------+
| Variable_name | Value           |
+---------------+-----------------+
| tx_isolation  | REPEATABLE-READ |
+---------------+-----------------+
mysql1> BEGIN;
mysql1> SET @x := (SELECT x FROM foo LIMIT 1);

mysql2> UPDATE foo SET x = x+1;
[gets a lock wait]

mysql3> SHOW ENGINE INNODB STATUS;
...
---TRANSACTION 228746, ACTIVE 22 sec
2 lock struct(s), heap size 360, 1 row lock(s)
MySQL thread id 58, OS thread handle 0x7fc262a1c700, query id 8163
  192.168.56.1 root cleaning up
TABLE LOCK table `test`.`foo` trx id 228746 lock mode IS
RECORD LOCKS space id 801 page no 3 n bits 80 index `PRIMARY` 
  of table `test`.`foo` trx id 228746 lock mode S
...

あなたがログに記録したバグで説明されているように、バグ #67452 選択から変数を設定すると、 read uncommitted を使用するとロックが取得されます。この動作はおそらく設計によるものです。SELECT次のケースのように、結果がデータの変更に使用されるステートメントと同じカテゴリに分類されるようです。

http://dev.mysql.com/doc/refman/5.6/en/innodb-locks-set.html

コンストラクトREPLACE INTO t SELECT ... FROM s WHERE ...またはで SELECT が使用されるとUPDATE t ... WHERE col IN (SELECT ... FROM s ...)、 InnoDB は table の行に共有次キー ロックを設定しますs

次のキー ロックの理由は、SELECT結果をより安定させるためです。つまり、またはその他のデータ変更ステートメントSELECTに使用されている間に、 によって一致する行が変更されることは望ましくありません。UPDATE

tx_isolation がであっても、これは重要です。 InnoDB はforステートメントが の一部として実行されるときにREPEATABLE-READサポートしないためです。REPEATABLE-READSELECTUPDATE


あなたのコメントについて:

ドキュメントに関係なく、次のことが起こります。

プレーンSELECTステートメントを実行すると、 InnoDB は、 を除くトランザクション分離で何もロックしませんSERIALIZABLE

SELECT ... LOCK IN SHARE MODEまたはを実行するSELECT ... FOR UPDATEと、もちろんロックされます。

ただしSELECT、データ変更ステートメントの一部としてINSERT INTO...SELECTまたは のサブクエリで実行する場合、UPDATEまたは で見つかったようにSET @variable := (SELECT...)、共有ロックを使用して、更新の進行中にデータが変更されないようにします。

ドキュメントは不完全な場合があります。テストしたほうがいいです。

于 2014-05-01T18:09:39.843 に答える
0

最初のステートメントはテーブルで SELECT を実行するため、トランザクションは 1 つの行で読み取りロックを取得します。

WHERE2 番目のトランザクションは、同じテーブル (句がないため、すべての行) で書き込みロックを取得しようとしますが、取得できません。

COMMITの後に(またはROLLBACK) コマンドを発行してSET @x = (...)、読み取りロックを解除する必要があります。

上記は間違っています。以下のコメントが興味深いかもしれないという理由だけで、この投稿を保持します。

于 2012-10-31T13:46:17.313 に答える