mita2 database life

主にMySQLに関するメモです

TiDB MySQLとの細かな非互換 - SELECT ~ FOR UPDATE は BEGIN しないとロックを取りにいかない

昨日に続き、TiDB の MySQL との非互換についてです。

mita2db.hateblo.jp

SELECT ~ FOR UPDATE は BEGIN しないとロックを取りにいかない

TiDB では、BEGIN / START TRANSACTION をせずに、SELECT ~ FOR UPDATE するとロックを取りません。 実際のアプリケーションの実装で、困ることはなさそうですが、検証などで SELECT ~ FOR UPDATE を使ってロックの状態を確認するときは、必ずトランザクションを張るよう気を付ける必要があります。

MySQL の場合

(当たり前ですが)「ロックを取る」側は ロックを持ち続けるために、明示的にトランザクションを開始してから SELECT ~ FOR UPDATE する必要があります。

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

mysql> SELECT * FROM tbl WHERE pk = 1 FOR UPDATE \G
*************************** 1. row ***************************
pk: 1
1 row in set (0.00 sec)

一方、「ロック解放を待つ」側は、トランザクションを明示的に開始しなくてもロックの解放を待ちます。

mysql> SELECT * FROM tbl WHERE pk = 1 FOR UPDATE \G
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction

TiDB の場合

同じようにロックを取ります。

mysql> BEGIN;
Query OK, 0 rows affected (0.01 sec)

mysql> SELECT * FROM tbl WHERE pk = 1 FOR UPDATE \G
*************************** 1. row ***************************
pk: 1
1 row in set (0.00 sec)

TiDB では、BEGIN しない SELECT ~ FOR UPDATE はロックしません。

mysql> SELECT * FROM tbl WHERE pk = 1 FOR UPDATE \G
*************************** 1. row ***************************
pk: 1
1 row in set (0.00 sec)

あまり目立たないですが、マニュアルの「Differences from MySQL InnoDB」に記載があります。

The autocommit SELECT FOR UPDATE statement does not wait for lock.

docs.pingcap.com