MySQL vs. TiDB-分散トランザクションの比較検証(8): TiDB分散トランザクションの基本動作

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

## はじめに

今回は、TiDB分散トランザクションの基本操作を検証します。

## 検証準備

### 端末を三つ用意します

- 端末1: TiDBクラスタを起動
- 端末2: クライアントからTiDBに接続
- 端末3: クライアントからTiDBに接続

### 端末1から、TiDBクラスタを起動

```
$ tiup playground --db 2 --pd 3 --kv 3
... ...
CLUSTER START SUCCESSFULLY, Enjoy it ^-^
To connect TiDB: mysql --comments --host 127.0.0.1 --port 4001 -u root -p (no password)
To connect TiDB: mysql --comments --host 127.0.0.1 --port 4000 -u root -p (no password)
To view the dashboard: http://127.0.0.1:2379/dashboard
PD client endpoints: [127.0.0.1:2379 127.0.0.1:2382 127.0.0.1:2384]
To view the Prometheus: http://127.0.0.1:9090
To view the Grafana: http://127.0.0.1:3000
```

### 端末2から、TiDBに接続

- tiupコマンドでTiDBに接続

```
$ tiup client
```

Enterキーで、ポート番号4000を選択すると、
コマンドプロンプトが表示されます。

```
my:root@127.0.0.1:4000=>
```

- データベース`test`を作成/指定

```
CREATE DATABASE test;
USE test;
```

- テーブル`theater`を作成
```
=> CREATE TABLE theater (
  seat_id INT PRIMARY KEY,
  ordered ENUM('YES', 'NO') DEFAULT 'NO'
);
CREATE TABLE
```

## 検証1: 通常パターン

分散トランザクションの基本操作を確認します。

### 端末2から、分散トランザクション開始

```
=> START TRANSACTION;
START TRANSACTION
```

- テーブル`theater`に1レコードをINSERT

```
=> INSERT INTO theater VALUES (1, 'NO');
INSERT 1
```

- SELECT実行し、テーブル`theater`を検索
```
=> SELECT * FROM theater;
 seat_id | ordered
---------+---------
       1 | NO
(1 row)
```

あれー、コミットしていないのに、レコードが存在するぞ。。。

- 分散トランザクションモードを確認

```
=> select @@tidb_txn_mode;
 @@tidb_txn_mode
-----------------
 pessimistic
(1 row)
```

デフォルトの悲観的モードになっています。

- 分散トランザクションのステータスを確認

```
=> select * from information_schema.tidb_trx\G
*************************** 1. row ***************************
ID: 433109652995047425
START_TIME: 2022-05-10T20:30:08.996+09:00
CURRENT_SQL_DIGEST:
CURRENT_SQL_DIGEST_TEXT:
STATE: Idle
WAITING_START_TIME:
MEM_BUFFER_KEYS: 1
MEM_BUFFER_BYTES: 29
SESSION_ID: 407
USER: root
DB: test
ALL_SQL_DIGESTS: ["f53534242526f5f17dd442bf4429823244510563047efdcc0679741ca5833ea6","93ee0752065c0824a984aa0eca2e59e4aedbee5479ae07ed29b924ff5bb09256","157bfd65d62eed0b262a745b7a2d6a37570576ab88b44f56a60d6f0e4e99eeba","c4ef5a83e75b42191d7e4e51ff33f5a712b8b41e743952a668b405076ce134ac","d7815f6adab7ceebe67882038b7d29c081675c0e94751110ff74213523b6998e"]
```

`STATE: Idle`状態になっています。

### 端末3から、別セッションでTiDBに接続

```
$ tiup client
```

- データベース`test`を指定
```
=> USE test;
USE
```

- SELECT実行し、テーブル`theater`を検索
```
=> SELECT * FROM theater;
(0 rows)
```

同じセッションではレコード確認できたので、別セッションからは確認できません。
なんだ、コミットされたのではなく、下書き(Prewrite)されただけか(分散トランザクションの第1フェーズ)。

### 端末2から、分散トランザクションをコミット

```
=> COMMIT;
COMMIT
```

- 分散トランザクションのステータスを確認

```
=> select * from information_schema.tidb_trx\G
```

分散トランザクションがコミットされ終了したため、存在しません。

### 端末3から、再度テーブルを検索

- SELECT実行し、テーブル`theater`を検索
```
=> SELECT * FROM theater;
 seat_id | ordered
---------+---------
       1 | NO
(1 row)
```

今度は、コミットされたため、レコードが存在します。

## 検証2: 異常パターン

操作途中でクライアントが異常終了した、といったシナリオです。

### 端末2から、分散トランザクション開始

```
=> START TRANSACTION;
START TRANSACTION
```

- テーブル`theater`に、1レコードをINSERT

```
=> INSERT INTO theater VALUES (2, 'NO');
INSERT 1
```

- SELECT実行し、テーブル`theater`を検索
```
=> SELECT * FROM theater;
 seat_id | ordered
---------+---------
       1 | NO
       2 | NO
(2 rows)
```

下書き(Prewrite)された(コミットはまだ)ので、
同じセッションから、`seat_id=2`の新しいレコードを確認できます。

- 分散トランザクションのステータスを確認

```
=> select * from information_schema.tidb_trx\G
*************************** 1. row ***************************
ID: 433110027008999425
START_TIME: 2022-05-10T20:53:55.746+09:00
CURRENT_SQL_DIGEST:
CURRENT_SQL_DIGEST_TEXT:
STATE: Idle
WAITING_START_TIME:
MEM_BUFFER_KEYS: 1
MEM_BUFFER_BYTES: 29
SESSION_ID: 407
USER: root
DB: test
ALL_SQL_DIGESTS: ["f53534242526f5f17dd442bf4429823244510563047efdcc0679741ca5833ea6","93ee0752065c0824a984aa0eca2e59e4aedbee5479ae07ed29b924ff5bb09256","157bfd65d62eed0b262a745b7a2d6a37570576ab88b44f56a60d6f0e4e99eeba","d7815f6adab7ceebe67882038b7d29c081675c0e94751110ff74213523b6998e"]
```

`STATE: Idle`状態になっています。

- ここで、`Ctrl+D`でセッションを強制終了


### 端末3から、別セッションで分散トランザクションを確認

```
=> select * from information_schema.tidb_trx\G
```

既に、トランザクションは存在しません(ロールバックされたか)。

- SELECT実行し、テーブル`theater`を検索
```
=> SELECT * FROM theater;
 seat_id | ordered
---------+---------
       1 | NO
(1 row)
```

結果、端末2でINSERTした`seat_id=2`のレコードは存在しません。

以前、[MySQL XAで実施した同じ検証](https://qiita.com/mingchun_zhao/items/803bd99181974f63f4ce#%E6%A4%9C%E8%A8%BC2-%E7%95%B0%E5%B8%B8%E3%83%91%E3%82%BF%E3%83%BC%E3%83%B3)と比較すると、
MySQLの場合は、`XA PREPARE`直後にセッション異常終了しても、
別セッションから`XA COMMIT`続行できましたね。

## TiDB vs. MySQL

分散トランザクションの基本動作確認から、

- 分散トランザクションのSQL操作は、TiDBがMySQLよりシンプルでした
- セッション異常終了時に、両者の挙動に差異が存在していました

## 終わりに

TiDB分散トランザクションの基本動作を確認しました。
次回は、TiDB分散トランザクションの例として、銀行振込みを検証してみます。
お楽しみに。

##### [次回] [MySQL vs. TiDB-分散トランザクションの比較検証(9): TiDBで銀行振込みのシミュレーション](https://qiita.com/mingchun_zhao/items/d0f9179ddb65e4f9e225)