「メタデータロックって何？」触って学ぶメタデータロックの世界

この記事は [トラストバンクAdventCalendar2024](https://qiita.com/advent-calendar/2024/trustbank) 18日目の記事になります。
担当は、ふるさとチョイス バックエンドエンジニアの @arinc0 です。

これまで業務の中で特に意識していなかった「メタデータロック」について、理解を深めることができました。
その経験と知識を共有するために、できるだけわかりやすくまとめてみたいと思います。

# はじめに
この記事では、実際にコードを実行しながら「メタデータロック」についての理解を深めていきます。

記事の内容を通して、
「メタデータロックという言葉は聞いたことがあるけどよくわからない」という人が、
「メタデータロックってこういうものなんだな」と理解してもらえたらいいなと思ってます。

実行したコードに対しての出力も記載しているので、手を動かさなくても十分理解できると思います。

:::note info
※ 登場するコードは、MySQL: 5.7.23で実行しています。
:::


# 1. 事前知識
### 1-1. ロックの種類
MySQLには大きく分けて２つのロックがあります
    - InnoDBロック[^1]
    - メタデータロック[^2]

普段意識することや、使ったことが多いのは、InnoDBロックの方かなと思います。


### 1-2. メタデータロック
MySQLでは、メタデータロックを使用してデータベースオブジェクトへの同時アクセスを管理し、データの一貫性を確保しています。

メタデータロックはテーブルのみではなく以下のものにも適用されます。
- スキーマ
- ストアドプログラム(プロシージャ、ファンクション、トリガーなど)
- テーブルスペース
- GET_LOCK() 関数で取得されたユーザーロック
- ロックサービスで取得されたロック

### 1-3. メタデータロックの種類
MDL(メタデータロック)には大きく分けると以下の２種類あります。
- 共有MDL
- 排他MDL

2種類のロックの関係は以下のようにまとめることができます。

<table>
<caption>共有MDLと排他MDLの関係
<thead>
<tr><th><th>共有MDL<th>排他MDL
<tbody>
<tr><tr><td>共有MDL<td>:white_check_mark: 競合しない<td>:boom: 競合する
<tr><tr><td>排他MDL<td>:boom: 競合する<td>:boom: 競合する
</table>

:::note
1. 共有MDLが取得されている場合、共有MDLは取得できる
1. 共有MDLが取得されている場合、排他MDLはロック取得待ちになる
1. 排他MDLが取得されている場合、共有MDLはロック取得待ちになる
1. 排他MDLが取得されている場合、排他MDLはロック取得待ちになる
1. 排他MDLがロック取得待ち状態の場合、後続のMDL取得もロック取得待ちの状態になる
:::

1-4は上記の関係から読み取ることができます。
5はロックの仕組み上そうなっているらしいです。

今回はこの5つのうち1, 2, 5を実際に検証したいと思います。
(3, 4は長めのDDL[^3]が実行されるテーブルを用意しないといけないため今回は検証しない。)

# 2. テーブルの準備
PK として id を持つテーブルを作成します。
```sql
CREATE TABLE samples (
    id int unsigned NOT NULL AUTO_INCREMENT,
    PRIMARY KEY (id)
) DEFAULT CHARSET=utf8mb4;
```
でテーブルを作って、

```sql
mysql> show create table samples \G;
*************************** 1. row ***************************
       Table: samples
Create Table: CREATE TABLE `samples` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
1 row in set (0.00 sec)

ERROR:
No query specified

```
定義はこんな感じで、

```sql
INSERT INTO samples VALUES();
```
1つだけレコードを入れておきます。

# 3. 共有MDLをかけてみよう！
まずは共有MDLをかけてみます。
共有MDLをかけるには、`SELECT`, `INSERT`, `UPDATE`, `DELETE` のいずれかを実行します。
- `SELECT`は共有MDL(read)を取得
- それ以外は共有MDL(write)を取得

MDLがかかる期間はトランザクションの終了までです。
普通に実行すると一瞬でMDLが`取得 => 解放`されます。
そのため、明示的にトランザクションを開始することでロックの期間を伸ばします。

## 3-1. 共有MDL(read) をかけてみる
トランザクションを開始して、SELECTします。
```sql
-- トランザクション開始
mysql> BEGIN;
Query OK, 0 rows affected (0.00 sec)


-- SELECT実行
mysql> select * from samples;
+----+
| id |
+----+
|  1 |
+----+
1 row in set (0.00 sec)
```

ロック状態を見ます。
ロック情報は `performance_schema.metadata_locks` から取得できます。

```sql
mysql> select OBJECT_TYPE, LOCK_TYPE, LOCK_DURATION, LOCK_STATUS from performance_schema.metadata_locks WHERE OBJECT_NAME="samples";
+-------------+-------------+---------------+-------------+
| OBJECT_TYPE | LOCK_TYPE   | LOCK_DURATION | LOCK_STATUS |
+-------------+-------------+---------------+-------------+
| TABLE       | SHARED_READ | TRANSACTION   | GRANTED     |
+-------------+-------------+---------------+-------------+
1 row in set (0.01 sec)
```

<details>
<summary>整形されたSQL</summary>

```sql
select
    -- 不要なカラムを一部省略
    OBJECT_TYPE, LOCK_TYPE, LOCK_DURATION, LOCK_STATUS
from
    performance_schema.metadata_locks
where
    -- 対象がテーブルの場合テーブル名
    OBJECT_NAME="samples";
```
</details>

:::note info
- `OBJECT_TYPE=TABLE`　→　対象がテーブルであることを表す
- `LOCK_TYPE=SHARED_READ`　→　共有MDL(read)であることを表す
- `LOCK_DURATION=TRANSACTION`　→　ロックの期間がトランザクション終了までであることを表す
- `LOCK_STATUS=GRANTED`　→　ロックが取得されている状態を表す
:::

トランザクションを終了
```sql
-- トランザクション終了
COMMIT;
```

ロック状態の確認をすると、ロックが解放されている。
```sql
mysql> select OBJECT_TYPE, LOCK_TYPE, LOCK_DURATION, LOCK_STATUS from performance_schema.metadata_locks WHERE OBJECT_NAME="samples";
Empty set (0.00 sec)
```

## 3-2. 共有MDL(write) をかけてみる
UPDATEを実行する。

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

-- UPDATE実行
mysql> UPDATE samples SET id=1 WHERE id=1;
Query OK, 0 rows affected (0.00 sec)
Rows matched: 1  Changed: 0  Warnings: 0

-- ロック状態確認
mysql> select OBJECT_TYPE, LOCK_TYPE, LOCK_DURATION, LOCK_STATUS from performance_schema.metadata_locks WHERE OBJECT_NAME="samples";
+-------------+--------------+---------------+-------------+
| OBJECT_TYPE | LOCK_TYPE    | LOCK_DURATION | LOCK_STATUS |
+-------------+--------------+---------------+-------------+
| TABLE       | SHARED_WRITE | TRANSACTION   | GRANTED     |
+-------------+--------------+---------------+-------------+
1 row in set (0.00 sec)
```

`LOCK_TYPE=SHARED_WRITE` となっていて、共有MDL(write)となっている。

# 4. パターン1の検証
「共有MDLが取得されている場合、共有MDLは取得できる」を検証します。

ここからはセッションAとセッションBを使用します。
ロックの確認はどっちのセッションで行ってもいいです。

## 4-1. 検証
セッションAで共有MDL(read)をかけます。
```sql:セッションA
-- トランザクション開始
mysql> BEGIN;
Query OK, 0 rows affected (0.00 sec)

-- 共有MDL（read）取得
mysql> select * from samples;
+----+
| id |
+----+
|  1 |
+----+
1 row in set (0.00 sec)

-- 確認
mysql> select OBJECT_TYPE, LOCK_TYPE, LOCK_DURATION, LOCK_STATUS, OWNER_THREAD_ID from performance_schema.metadata_locks WHERE OBJECT_NAME="samples";
+-------------+-------------+---------------+-------------+-----------------+
| OBJECT_TYPE | LOCK_TYPE   | LOCK_DURATION | LOCK_STATUS | OWNER_THREAD_ID |
+-------------+-------------+---------------+-------------+-----------------+
| TABLE       | SHARED_READ | TRANSACTION   | GRANTED     |           14660 |
+-------------+-------------+---------------+-------------+-----------------+
1 row in set (0.00 sec)
```
<details>
<summary>ロック状態確認SQL(整形済み)</summary>

```sql
select
    -- セッションの区別をつけるため OWNER_THREAD_ID を追加した
    OBJECT_TYPE, LOCK_TYPE, LOCK_DURATION, LOCK_STATUS, OWNER_THREAD_ID
from
    performance_schema.metadata_locks
WHERE
    OBJECT_NAME="samples";
```
</details>


スレッド(ID:14660)で共有MDL(read)が取得されました。

セッションBで共有MDL(write)をかけます。
```sql:セッションB
-- トランザクション開始
mysql> BEGIN;
Query OK, 0 rows affected (0.00 sec)

-- 共有MDL（write）取得
mysql> UPDATE samples SET id=1 WHERE id=1;
Query OK, 0 rows affected (0.00 sec)
Rows matched: 1  Changed: 0  Warnings: 0

-- 確認
mysql> select OBJECT_TYPE, LOCK_TYPE, LOCK_DURATION, LOCK_STATUS, OWNER_THREAD_ID from performance_schema.metadata_locks WHERE OBJECT_NAME="samples";
+-------------+--------------+---------------+-------------+-----------------+
| OBJECT_TYPE | LOCK_TYPE    | LOCK_DURATION | LOCK_STATUS | OWNER_THREAD_ID |
+-------------+--------------+---------------+-------------+-----------------+
| TABLE       | SHARED_READ  | TRANSACTION   | GRANTED     |           14660 |
| TABLE       | SHARED_WRITE | TRANSACTION   | GRANTED     |           14710 |
+-------------+--------------+---------------+-------------+-----------------+
2 rows in set (0.01 sec)
```

ロック状態を確認すると、両方ともロックが取れてます。
- スレッド(ID:14660)で共有MDL(read)
- スレッド(ID:14710)で共有MDL(write)

## 4-2. 検証結果
共有MDLが取得されている場合、共有MDLは取得できる。

# 5. パターン２の検証
「共有MDLが取得されている場合、排他MDLはロック取得待ちになる」を検証します。

## 5-1. 検証
セッションAで共有MDLを取得。
```sql:セッションA
-- トランザクション開始
mysql> BEGIN;
Query OK, 0 rows affected (0.00 sec)

-- 共有MDL取得
mysql> select * from samples;
+----+
| id |
+----+
|  1 |
+----+
1 row in set (0.00 sec)

-- 確認
mysql> select OBJECT_TYPE, LOCK_TYPE, LOCK_DURATION, LOCK_STATUS, OWNER_THREAD_ID from performance_schema.metadata_locks WHERE OBJECT_NAME="samples";
+-------------+-------------+---------------+-------------+-----------------+
| OBJECT_TYPE | LOCK_TYPE   | LOCK_DURATION | LOCK_STATUS | OWNER_THREAD_ID |
+-------------+-------------+---------------+-------------+-----------------+
| TABLE       | SHARED_READ | TRANSACTION   | GRANTED     |           14660 |
+-------------+-------------+---------------+-------------+-----------------+
1 row in set (0.00 sec)
```

セッションBから排他MDLを取得。

排他MDLを取得するには、DDLを実行します。
以下のALTERを実行します。
```sql:セッションB
-- nameカラム(文字列)を追加
ALTER TABLE samples ADD COLUMN name varchar(255), ALGORITHM=INPLACE, LOCK=SHARED;
```
:::note warn
MySQLのバージョン5.7で検証しているため、
`ALGORITHM`と`LOCK`で指定できる値がMySQL8.0以降と若干異なります。
必要に応じて公式ドキュメントで確認してください。

https://dev.mysql.com/doc/refman/8.0/ja/innodb-online-ddl-operations.html
:::

:::note
`LOCK=SHARED`のロックは、InnoDBロック[^2]です。

このDDLの実行中にはInnoDBの共有ロックがかかります。
※ SELECTは実行できるが、DML[^4]は実行できないロックです。
:::
ALTER実行したまま結果が返ってこないので、他のセッションからロック状態を確認します。

```sql:セッションA
mysql> select OBJECT_TYPE, LOCK_TYPE, LOCK_DURATION, LOCK_STATUS, OWNER_THREAD_ID from performance_schema.metadata_locks WHERE OBJECT_NAME="samples";
+-------------+-------------------+---------------+-------------+-----------------+
| OBJECT_TYPE | LOCK_TYPE         | LOCK_DURATION | LOCK_STATUS | OWNER_THREAD_ID |
+-------------+-------------------+---------------+-------------+-----------------+
| TABLE       | SHARED_READ       | TRANSACTION   | GRANTED     |           14660 |
| TABLE       | SHARED_UPGRADABLE | TRANSACTION   | GRANTED     |           14710 |
| TABLE       | EXCLUSIVE         | TRANSACTION   | PENDING     |           14710 |
+-------------+-------------------+---------------+-------------+-----------------+
3 rows in set (0.00 sec)
```

スレッド(ID:14710)は以下の状態です。
- 共有MDL(アップグレード可能)[^5]が取得済み
- 排他MDLが保留中(PENDING)

ロック取得待ちの状態は `information_schema.PROCESSLIST`[^6] から確認できます。
```sql:セッションA
mysql> select ID, COMMAND, STATE, INFO from information_schema.PROCESSLIST;
+-------+---------+---------------------------------+----------------------------------------------------------------------------------+
| ID    | COMMAND | STATE                           | INFO                                                                             |
+-------+---------+---------------------------------+----------------------------------------------------------------------------------+
| 14685 | Query   | Waiting for table metadata lock | ALTER TABLE samples ADD COLUMN name varchar(255), ALGORITHM=INPLACE, LOCK=SHARED |
| 14635 | Query   | executing                       | select ID, COMMAND, STATE, INFO from information_schema.PROCESSLIST              |
+-------+---------+---------------------------------+----------------------------------------------------------------------------------+
2 rows in set (0.00 sec)
```

`ALTER TABLE` が `Waiting for table metadata lock` となっていてメタデータロック取得待ちだということがわかります。


セッションAでトランザクションをコミットしましょう。
```sql:セッションA
COMMIT;
```

セッションBの`ALTER TABLE`が実行されました。
```sql:セッションB
-- 結果待ちだった状態から、実行され結果が返ってくる。
mysql> ALTER TABLE samples ADD COLUMN name varchar(255), ALGORITHM=INPLACE, LOCK=SHARED;
Query OK, 0 rows affected (9 min 59.59 sec)
Records: 0  Duplicates: 0  Warnings: 0

-- テーブル定義を確認
mysql> show create table samples \G;
*************************** 1. row ***************************
       Table: samples
Create Table: CREATE TABLE `samples` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(255) DEFAULT NULL, -- name が追加されている！
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4
1 row in set (0.00 sec)

ERROR:
No query specified
```

nameが追加されてますね。

## 5-2. 検証結果
共有MDLが取得されている場合、排他MDLはロック取得待ちになる。

# 6. パターン５の検証
「排他MDLがロック取得待ち状態の場合、後続のMDL取得もロック取得待ちの状態になる」を検証します。

## 6-1. 検証
```sql:セッションA
-- トランザクション開始
mysql> BEGIN;
Query OK, 0 rows affected (0.00 sec)

-- 共有MDL(read)
mysql> select * from samples;
+----+------+
| id | name |
+----+------+
|  1 | NULL |
+----+------+
1 row in set (0.01 sec)

-- 確認
mysql> select OBJECT_TYPE, LOCK_TYPE, LOCK_DURATION, LOCK_STATUS, OWNER_THREAD_ID from performance_schema.metadata_locks WHERE OBJECT_NAME="samples";
+-------------+-------------+---------------+-------------+-----------------+
| OBJECT_TYPE | LOCK_TYPE   | LOCK_DURATION | LOCK_STATUS | OWNER_THREAD_ID |
+-------------+-------------+---------------+-------------+-----------------+
| TABLE       | SHARED_READ | TRANSACTION   | GRANTED     |           14660 |
+-------------+-------------+---------------+-------------+-----------------+
1 row in set (0.00 sec)
```

以下のALTERを実行します。
```sql:セッションB
-- name カラムを削除
mysql> ALTER TABLE samples DROP COLUMN name, ALGORITHM=INPLACE, LOCK=NONE;
```

結果が返ってこないので別セッションでロック状態の確認をします。
```sql:セッションA
-- ロック状態確認
mysql> select OBJECT_TYPE, LOCK_TYPE, LOCK_DURATION, LOCK_STATUS, OWNER_THREAD_ID from performance_schema.metadata_locks WHERE OBJECT_NAME="samples";
+-------------+-------------------+---------------+-------------+-----------------+
| OBJECT_TYPE | LOCK_TYPE         | LOCK_DURATION | LOCK_STATUS | OWNER_THREAD_ID |
+-------------+-------------------+---------------+-------------+-----------------+
| TABLE       | SHARED_READ       | TRANSACTION   | GRANTED     |           14660 |
| TABLE       | SHARED_UPGRADABLE | TRANSACTION   | GRANTED     |           14710 |
| TABLE       | EXCLUSIVE         | TRANSACTION   | PENDING     |           14710 |
+-------------+-------------------+---------------+-------------+-----------------+
3 rows in set (0.00 sec)

-- ロック取得待ちを確認
mysql> select ID, COMMAND, STATE, INFO from information_schema.PROCESSLIST;
+-------+---------+---------------------------------+---------------------------------------------------------------------+
| ID    | COMMAND | STATE                           | INFO                                                                |
+-------+---------+---------------------------------+---------------------------------------------------------------------+
| 14685 | Query   | Waiting for table metadata lock | ALTER TABLE samples DROP COLUMN name, ALGORITHM=INPLACE, LOCK=NONE  |
| 14635 | Query   | executing                       | select ID, COMMAND, STATE, INFO from information_schema.PROCESSLIST |
+-------+---------+---------------------------------+---------------------------------------------------------------------+
2 rows in set (0.00 sec)
```
下記の状態であることがわかります。
- 排他MDLが保留中(PENDING)
- DDLがロック取得待ち(`Waiting for table metadata lock`)

```sql:セッションC
-- 止まる
mysql> select * from samples;
```
結果が返ってこないので別セッションでロック状態の確認をします。

```sql:セッションA
-- ロック状態確認
mysql> select OBJECT_TYPE, LOCK_TYPE, LOCK_DURATION, LOCK_STATUS, OWNER_THREAD_ID from performance_schema.metadata_locks WHERE OBJECT_NAME="samples";
+-------------+-------------------+---------------+-------------+-----------------+
| OBJECT_TYPE | LOCK_TYPE         | LOCK_DURATION | LOCK_STATUS | OWNER_THREAD_ID |
+-------------+-------------------+---------------+-------------+-----------------+
| TABLE       | SHARED_READ       | TRANSACTION   | GRANTED     |           14660 |
| TABLE       | SHARED_UPGRADABLE | TRANSACTION   | GRANTED     |           14710 |
| TABLE       | EXCLUSIVE         | TRANSACTION   | PENDING     |           14710 |
| TABLE       | SHARED_READ       | TRANSACTION   | PENDING     |           14965 |
+-------------+-------------------+---------------+-------------+-----------------+
4 rows in set (0.00 sec)

-- ロック取得待ちを確認
mysql> select ID, COMMAND, STATE, INFO from information_schema.PROCESSLIST;
+-------+---------+---------------------------------+---------------------------------------------------------------------+
| ID    | COMMAND | STATE                           | INFO                                                                |
+-------+---------+---------------------------------+---------------------------------------------------------------------+
| 14685 | Query   | Waiting for table metadata lock | ALTER TABLE samples DROP COLUMN name, ALGORITHM=INPLACE, LOCK=NONE  |
| 14940 | Query   | Waiting for table metadata lock | select * from samples                                               |
| 14635 | Query   | executing                       | select ID, COMMAND, STATE, INFO from information_schema.PROCESSLIST |
+-------+---------+---------------------------------+---------------------------------------------------------------------+
3 rows in set (0.00 sec)

```

以下状態が確認できます。
- スレッド(ID:14965)が共有MDL(read)取得待ち(PENDING)
- `select * from samples` が、MDL取得待ち

セッションAで`COMMIT`すると後続のロックが取得できるようになるので、セッションB、セッションCで実行結果が返ってきます。

```sql:セッションB
-- 実行される
mysql> ALTER TABLE samples DROP COLUMN name, ALGORITHM=INPLACE, LOCK=NONE;
Query OK, 0 rows affected (6 min 35.55 sec)
Records: 0  Duplicates: 0  Warnings: 0

-- テーブル定義更新されている
-- name カラムが削除された
mysql> show create table samples \G;
*************************** 1. row ***************************
       Table: samples
Create Table: CREATE TABLE `samples` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4
1 row in set (0.00 sec)

ERROR:
No query specified
```

```sql:セッションC
-- 実行される
mysql> select * from samples;
+----+------+
| id | name |
+----+------+
|  1 | NULL |
+----+------+
1 row in set (3 min 46.80 sec)
```

## 6-2. 検証結果
排他MDLがロック取得待ち状態の場合、後続のMDL取得もロック取得待ちの状態になる。

# まとめ
:::note
1. 共有MDLが取得されている場合、共有MDLは取得できる
1. 共有MDLが取得されている場合、排他MDLはロック取得待ちになる
1. 排他MDLが取得されている場合、共有MDLはロック取得待ちになる
1. 排他MDLが取得されている場合、排他MDLはロック取得待ちになる
1. 排他MDLがロック取得待ち状態の場合、後続のMDL取得もロック取得待ちの状態になる
:::

今回は上記のうち、1, 2, 5について検証しました。

MySQLでDDLを実行する上で、これらの挙動の理解はとても大切です。
実際に下記のような問題が発生することもあります。


```mermaid
sequenceDiagram
  participant A as セッションA
  participant T as テーブル
  participant B as セッションB
  participant C as セッションC
  
  A->>+A: トランザクション開始
  A->>T: SELECT実行
  T-->>A: 共有MDL取得
  
  B->>T: DDL実行
  T-->>+B: 共有MDLが解放されるまで待ってね

  C->>T: SELECT実行
  T-->>C: 排他MDLがロック取得して解放するまで待ってね
  A->>-A: Commit
  A->>T: 共有MDL解放
  
  T-->>B: 排他MDL取得
  B->>-T: 排他MDL解放

  T-->>C: 共有MDL取得
```

まさに5のパターンですが、この場合セッションAのトランザクションが永遠に終わらなければ障害が発生します。
具体的には、セッションBがDDLを実行した瞬間からテーブルへの後続のクエリー[^7], DML, DDLが全て止まり続けます[^8]。


できるだけサービスを止めずにテーブル定義を変更していくために、学ぶべきことはたくさんあるなと思いました。

# 終わりに
弊社では絶賛エンジニア募集中です！
気になった方、是非お気軽に[Wantedly](https://www.wantedly.com/companies/trustbank/projects)からご連絡ください！

[^1]: https://dev.mysql.com/doc/refman/8.0/ja/innodb-locking.html
[^2]: https://dev.mysql.com/doc/refman/8.0/ja/metadata-locking.html
[^3]: [データ定義言語 Data Definition Language](https://dev.mysql.com/doc/refman/8.0/ja/glossary.html#glos_ddl)
[^4]: [データ操作言語 Data Manipulation Language](https://dev.mysql.com/doc/refman/8.0/ja/glossary.html#glos_dml)
[^5]: オンラインDDLはフェーズの中で、最初にアップグレード可能な共有MDLが取得され、最後に排他MDLへアップグレードされます。
公式ドキュメントの、[オンライン DDL のパフォーマンスと同時実行性](https://dev.mysql.com/doc/refman/8.0/ja/innodb-online-ddl-performance.html)に詳しく記載されています。
[^6]: https://dev.mysql.com/doc/refman/8.0/ja/performance-schema-processlist-table.html
[^7]: [SELECTのこと](https://dev.mysql.com/doc/refman/8.0/ja/glossary.html#glos_query)
[^8]: 実際には [lock_wait_timeout](https://dev.mysql.com/doc/refman/8.0/ja/server-system-variables.html#sysvar_lock_wait_timeout)で設定されている時間ロック取得を待ち続けます。