メニューを閉じる

テクノデジタルグループ

メニューを開く

2018.05.30

DB

MySQL8で、排他ロックされたレコードがスキップできるようになった。

こんにちは、MTです。
今回は、MySQL8で SKIP LOKEDNOWAIT の2機能が追加されたので、実際に試してみました。

どちらも行ロックに関する機能で、

  • SKIP LOCKED
    • ロック対象のレコードが既にロックされている場合はスキップする。
  • NOWAIT
    • ロック対象のレコードが既にロックされている場合は、直ちに失敗にする。

というものです。
他のDBには同等の機能が備わっていたりするのですが、MySQLはやっと提供されたかという感じです。

従来(MySQL5.7まで)は上記のような機能は提供されていなかったので、

  • 既にロックされていた場合は、ロック待ちタイムアウトまで待ち続ける

  • ロック用のカラムで頑張る

方法を取るしかありませんでした。

-- トランザクションA
mysql> BEGIN;
Query OK, 0 rows affected (0.00 sec)

mysql> SELECT * FROM user WHERE id = 1 FOR UPDATE;
+----+------+
| id | name |
+----+------+
| 1 | sato |
+----+------+
1 row in set (0.00 sec)


-- トランザクションB
mysql> BEGIN;
Query OK, 0 rows affected (0.00 sec)

-- トランザクションA で id が 1 のレコードはロックされているので、待ち続ける。
mysql> SELECT * FROM user WHERE id = 1 FOR UPDATE;
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction

 

ロックされていた場合は直ちにエラーを返してきてほしいものですが、そのような機能は無いので待ち続けるしかありません。
また、ロックを判断するためのカラムに関しては、MySQLの仕組みにテーブル構造が引きずられてるので、できるだけ避けたい。
今回追加された SKIP LOCKED、NOWAIT は、上記の問題を解決します。

準備

まずはデータの準備から。
IDと名前だけの user テーブルを作成し、データを登録します。

mysql> CREATE TABLE user (
->   id INT PRIMARY KEY
-> , name VARCHAR(255) NOT NULL 
-> );
Query OK, 0 rows affected (0.11 sec)

mysql> INSERT INTO user VALUES
->   (0, 'tanaka')
-> , (1, 'sato')
-> , (2, 'matsumoto');
Query OK, 3 rows affected (0.03 sec)
Records: 3 Duplicates: 0 Warnings: 0

mysql> SELECT * FROM user;
+----+-----------+
| id | name      |
+----+-----------+
| 0 | tanaka     |
| 1 | sato       |
| 2 | matsumoto  |
+----+-----------+
3 rows in set (0.00 sec)

SKIP LOCKED – ロックされているレコードはスキップする

あるレコードを排他ロックする際、既にロックされている場合にはスキップする機能です。
例えば トランザクションAid1 のレコードをロックし、トランザクションB で全レコードをロックしようとした場合、
トランザクションA でロックした id1 のレコードは トランザクションB でスキップされます。

-- トランザクションA
-- id が 1 のレコードをロックする。
mysql> BEGIN;
Query OK, 0 rows affected (0.00 sec)

mysql> SELECT * FROM user WHERE id = 1 FOR UPDATE;
+----+------+
| id | name |
+----+------+
| 1 | sato  |
+----+------+
1 row in set (0.00 sec)
-- トランザクションB
-- 全レコードをロックする。
mysql> BEGIN;
Query OK, 0 rows affected (0.00 sec)

mysql> SELECT * FROM user FOR UPDATE SKIP LOCKED;
+----+-----------+
| id | name      |
+----+-----------+
| 0 | tanaka     |
| 2 | matsumoto  |
+----+-----------+
2 rows in set (0.00 sec)

id1 のレコードは抽出されていませんね。

NOWAIT – ロックされている場合は直ちにエラーにする

SKIP LOCKED は既にロックされていた場合にロックしない(スキップする)機能でしたが、NOWAIT はロックできないと分かった時点で直ちに失敗にするための機能です。
少し話を戻しますが、SELECT FOR UPDATE SKIP LOCKED の結果が「対象レコード無し」の場合、

「レコード自体が存在しない」のか「他でロックされている」のか

が分かりません。

-- トランザクションA
mysql> SELECT * FROM user WHERE id = 1 FOR UPDATE;
+----+------+
| id | name |
+----+------+
| 1 | sato  |
+----+------+
1 row in set (0.00 sec)
-- トランザクションB
mysql> SELECT * FROM user WHERE id = 1 FOR UPDATE SKIP LOCKED;
Empty set (0.00 sec)

業務要件上、上記のようなケースが許容されている場合は良いですが「処理対象データのロックが取れない」場合にはエラーに倒したい場合が多いのではないでしょうか。
かつ、ロックが取れないと判明した時点で即時に。
このような場合は NOWAIT を使用します。

-- トランザクションA
-- id が 1 のデータをロック。
mysql> BEGIN;
Query OK, 0 rows affected (0.00 sec)

mysql> SELECT * FROM user WHERE id = 1 FOR UPDATE;
+----+------+
| id | name |
+----+------+
| 1 | sato  |
+----+------+
1 row in set (0.01 sec)
-- トランザクションB でも id が 1 のデータをロック。
-- ただし、既にロックされている場合には直ちにエラーとする。
mysql> BEGIN;
Query OK, 0 rows affected (0.01 sec)

mysql> SELECT * FROM user WHERE id = 1 FOR UPDATE NOWAIT;
ERROR 3572 (HY000): Statement aborted because lock(s) could not be acquired immediately and NOWAIT is set.

文章だと分かりませんが、SELECT文を発行した直後にエラーが返ってきます。

まとめ

  • MySQL8で、ロックの制御に関する機能が追加された。
  • ロック済みレコードをスキップしたい場合には SKIP LOCKED
  • ロック済みの場合に直ちにエラーにしたい場合は NOWAIT

【記事への感想募集中!】

記事への感想・ご意見がありましたら、ぜひフォームからご投稿ください!
  • こんな記事が読んでみたい、こんなことが知りたい、調べてほしい!という意見も募集中!
  • いただいた感想は今後の記事に活かしたいと思います!

感想フォームはこちら


【テクノデジタルではエンジニア/デザイナーを積極採用中です!】

下記項目に1つでも当てはまる方は是非、詳細ページへ!
  • 自分でアプリを作ってみたい
  • ITで世の中にワクワクを生み出したい
  • 使いやすさ、デザインにこだわったWebサイトを開発したい

採用情報の詳細はこちら


Qangaroo(カンガルー)

  • 徹底した見やすさと優れた操作性で、テストの「見える化」を実現。
  • テストの進捗が見える。開発がスマートに進む。
  • クラウド型テスト管理ツール『Qangaroo(カンガルー)』

【テクノデジタルのインフラサービス】

当社では、多数のサービスの開発実績を活かし、
アプリケーションのパフォーマンスを最大限に引き出すインフラ設計・構築を行います。
AWSなどへのクラウド移行、既存インフラの監視・運用保守も承りますので、ぜひご相談ください。
詳細は下記ページをご覧ください。

https://www.tcdigital.jp/infrastructure/

最近の記事