MySQL vs. TiDB-分散トランザクションの比較検証(3): MySQL内部XA

##### [前回] [MySQL vs. TiDB-分散トランザクションの比較検証(2): MySQL XA](https://qiita.com/mingchun_zhao/items/803bd99181974f63f4ce)

## はじめに

前回に続き、MySQLの分散トランザクション、 XAの検証です。

## その前に、XAトランザクションの状態遷移のおさらい

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2523098/bf65ccb0-22cb-062f-85e4-8d6beaf571ce.png)

XAトランザクションの各種状態と遷移条件

- ACTIVE
    - `XA START`ステートメントにより、トランザクションがアクティブ状態に
    - ACTIVE状態で、READ/WRITE関連ステートメントを実行できる
- IDLE
    - `XA END`ステートメントにより、トランザクションがIDEL状態に
    - IDLE状態で、`XA PREPARE`または`XA COMMIT ONE PHASE`のいずれかを発行できる
- PREPARED
    - `XA PREPARE`ステートメントにより、トランザクションが準備されPREPARED状態に
- COMMITTED
    - `XA COMMIT`ステートメントにより、トランザクションがCOMMITTED状態になり終了
    - ※ `XA COMMIT ONE PHASE`は、トランザクションの準備&コミットを1ステップで実行
- FAILED
    - 処理中エラーにより、トランザクションが失敗しFAILED状態に
- ABORTED
    - `XA ROLLBACK`ステートメントにより、トランザクションがABORTED状態になり終了

## 検証開始

検証環境と事前準備は前回と同じです。
操作用端末を二つ開きます。

- 端末1: アプリケーション操作用
- 端末2: MySQLサーバー操作用

## 検証3: MySQLサーバー異常終了時のXA検証

前回は、MySQLクライアントが`XA PREPARE`直後に異常終了しても、
XAトランザクションが維持され、`XA COMMIT`できることを確認できました。
今回は、MySQLサーバー異常終了時のXAの挙動を検証します。

### 端末1から、XAトランザクションを実行
- mysqlコマンドでMySQL接続し、データベース指定
```
$ mysql -u user -p
mysql> USE test;
```
- XAトランザクションを開始
`myxa`は、XAトランザクションの一意識別子
```
mysql> XA START 'myxa';
```
- 1行INSERT
```
mysql> INSERT INTO theater VALUES (3, 'NO');
```
- `XA END`実行し、トランザクションをIDLE状態に
```
mysql> XA END 'myxa';
```
- `XA PREPARE`実行し、トランザクションを準備
```
mysql> XA PREPARE 'myxa';
```
- `XA RECOVER`実行し、PREPARED状態のXAトランザクションを確認
```
mysql> XA RECOVER;
+----------+--------------+--------------+------+
| formatID | gtrid_length | bqual_length | data |
+----------+--------------+--------------+------+
|        1 |            4 |            0 | myxa |
+----------+--------------+--------------+------+
1 row in set (0.00 sec)
```

### 端末2から、MySQLサーバーをkillコマンドで強制終了

- MySQLサーバーのプロセスIDを確認
```shell
$ ps -ef | grep mysqld | grep -v grep
mysql      303   152  0 06:21 ?        00:00:03 /usr/sbin/mysqld --basedir=/usr --datadir=/var/lib/mysql --plugin-dir=/usr/lib/mysql/plugin --log-error=/var/log/mysql/error.log --pid-file=81KRV93.pid
```
- プロセスID(上記例では303)を指定しkill
```shell
$ kill -9 <プロセスID>
```

### 端末1から、XAトランザクションを確認

- `XA RECOVER`コマンド実行します

```
mysql> XA RECOVER;
ERROR 2013 (HY000): Lost connection to MySQL server during query
No connection. Trying to reconnect...
Enter password:
ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/var/run/mysqld/mysqld.sock' (111)
ERROR:
Can't connect to the server
```

MySQLサーバーがkillされたため、接続すらできません。

- mysqlコマンドを終了します。
```
mysql> quit
```

### 端末2から、MySQLサーバーを再起動します

- MySQLサーバー起動
```
$ sudo service mysql start
```

### 端末1から、XAトランザクションを確認

- 再度、mysqlコマンドでMySQL接続し、データベース指定
```
$ mysql -u user -p
mysql> USE test;
```

- `XA RECOVER`実行し、PREPARED状態のXAトランザクションを確認

```
mysql> XA RECOVER;
+----------+--------------+--------------+------+
| formatID | gtrid_length | bqual_length | data |
+----------+--------------+--------------+------+
|        1 |            4 |            0 | myxa |
+----------+--------------+--------------+------+
1 row in set (0.00 sec)
```

なんと、PREPARED状態のXAトランザクションが残ってくれています。

- `XA COMMIT`実行し、PREPARED状態のトランザクションをコミット
```
mysql> XA COMMIT 'myxa';
```

- SELECT実行し、INSERTされたseat_id=3を検索
```
mysql> SELECT * FROM theater WHERE seat_id=3;
+---------+---------+
| seat_id | ordered |
+---------+---------+
|       3 | NO      |
+---------+---------+
1 row in set (0.00 sec)
```

結果、期待とおり1レコードヒットしました。
第1フェーズの`XA PREPARE`後、MySQLサーバーが異常終了しても、
第2フェーズの`XA COMMIT`を続行できました、すごい。

## おわりに

MySQL XAに対し、MySQLサーバー異常終了したらどうなるか検証しました。
次回も検証続きます、お楽しみに。

##### [次回] [MySQL vs. TiDB-分散トランザクションの比較検証(4): MySQL内部XA(続)](https://qiita.com/mingchun_zhao/items/043937d351a74f8d5e0a)