# TiDBのトランザクション隔離レベル

## 概要
+ これらの演習では、TiDBの2つの異なるトランザクション隔離レベルを体験します。

### 注意
+ いくつかのステップでは、2つの異なるターミナルウィンドウでコマンドを入力する必要があります。2つのターミナルを起動し、演習の間ずっと開いておくと便利でしょう。
+ この演習で利用する、`IP`、`port`、`username`、`password`、`directory`などは、あなたの環境と異なる場合があります。
+ ターミナルウィンドウの"`$`"とはOSプロンプトです。
+ ターミナルウィンドウ内の "`tidb>`" または "`mysql>`" は、SQL コマンドプロンプトです。
+ これらの演習は、ノートパソコンなどの単一のマシン上で実行することができます。

### 前提条件
+ macOSまたはLinuxを使用していること。
+ [lab repository](https://github.com/pingcap/tidb-course-201-lab.git)をクローン済みであること。
+ 演習「テスト用にTiDBクラスタを作成する」を完了していること。

## 演習 1：トランザクション隔離レベル - REPEATABLE-READ

### 概要
+ この演習では、`REPEATABLE-READ` 隔離レベルを体験します。

### 所要時間
+ この演習は約10分程度かかります。

### タスク
1. 2つのデータベースセッションを作成し、システム変数`transaction_isolation`が`REPEATABLE-READ`に設定されていることを確認します。
2. アクティブなトランザクションとコミットされたトランザクションからデータを異なるセッションから読み取ろうとしています。

### 手順
1. `connect-4000.sh`または`connect-4001.sh`を実行して、TiDB Playground クラスタTiDBサーバーに接続します。
   ```
   $ cd tidb-course-201-lab/scripts
   $ ./connect-4000.sh
   ...
   tidb:4000>
   ```

2. プロンプトを`Session A `に変更します。
   ```
   \R Session A>
   ```
   ```
   tidb:4000> \R Session A>
   PROMPT set to 'Session A> '
   Session A>
   ```

3. 新しいターミナルを開き、`connect-4000.sh`または`connect-4001.sh`を実行してTiDBサーバーに接続します。
   ```
   ./connect-4001.sh
   ...
   tidb:4001>
   ```

4. プロンプトを`Session B `に変更します。
   ```
   \R Session B>
   ```
   ```
   tidb:4001> \R Session B>
   PROMPT set to 'Session B> '
   Session B>
   ```

5. 両方のターミナルで、システム変数`transaction_isolation`が`REPEATABLE-READ`であることを確認します。
   ```sql
   SHOW SESSION VARIABLES LIKE 'transaction_isolation';
   ```
   ```
   Session A> SHOW SESSION VARIABLES LIKE 'transaction_isolation';
   --------------
   SHOW SESSION VARIABLES LIKE 'transaction_isolation'
   --------------

   +-----------------------+-----------------+
   | Variable_name | Value |
   +-----------------------+-----------------+
   | transaction_isolation | REPEATABLE-READ |
   +-----------------------+-----------------+
   1 row in set (0.01 sec)
   ```
   ```
   Session B> SHOW SESSION VARIABLES LIKE 'transaction_isolation';
   --------------
   SHOW SESSION VARIABLES LIKE 'transaction_isolation'
   --------------

   +-----------------------+-----------------+
   | Variable_name | Value |
   +-----------------------+-----------------+
   | transaction_isolation | REPEATABLE-READ |
   +-----------------------+-----------------+
   1 row in set (0.01 sec)
   ```

6. セッションAで、`test.ilevel`という名前のテーブルを作成し、そこに2行を挿入します。
   ```sql
   DROP TABLE IF EXISTS test.ilevel;
   CREATE TABLE test.ilevel (pk INT PRIMARY KEY, name CHAR(10));
   INSERT INTO test.ilevel VALUES (1, 'Moon Light'), (2, 'Sun Light');
   ```
   ```
   ...
   Query OK, 2 rows affected (0.01 sec)
   Records: 2 Duplicates: 0 Warnings: 0
   ```

7. セッションAに留まり、新しいトランザクションを開始してから、テーブル`test.ilevel`をクエリします。
   ```sql
   BEGIN;
   SELECT * FROM test.ilevel;
   ```
   ```
   Session A> BEGIN;
   --------------
   BEGIN
   --------------

   Query OK, 0 rows affected (0.00 sec)

   +----+------------+
   | pk | name |
   +----+------------+
   | 1 | Moon Light |
   | 2 | Sun Light |
   +----+------------+
   2 rows in set (0.00 sec)
   ```

8. セッションB（もう一方のターミナル）に変更し、行番号1のname列を`Moon Light`から`Mars Light`に変更します。
   ```sql
   BEGIN;
   UPDATE test.ilevel SET name='Mars Light' WHERE pk=1;
   COMMIT;
   SELECT * FROM test.ilevel;
   ```
   ```
   ...
   +----+------------+
   | pk | name |
   +----+------------+
   | 1 | Mars Light |
   | 2 | Sun Light |
   +----+------------+
   2 rows in set (0.01 sec)
   ```

9. セッションAに切り替えて、次のクエリを実行して結果を確認します。
   ```sql
   SELECT * FROM test.ilevel;
   ```
   ```
   ...
   +----+------------+
   | pk | name |
   +----+------------+
   | 1 | Moon Light |
   | 2 | Sun Light |
   +----+------------+
   2 rows in set (0.00 sec)
   ```

10. セッションAに留まり、トランザクション（COMMIT または ROLLBACK）を終了し、ステップ9で同じクエリを再実行すると、コミットされたデータが表示されます。
    ```sql
    COMMIT;
    SELECT * FROM test.ilevel;
    ```
    ```
    ...
    +----+------------+
    | pk | name |
    +----+------------+
    | 1 | Mars Light |
    | 2 | Sun Light |
    +----+------------+
    2 rows in set (0.00 sec)
    ```

11. 両方のセッションを接続したままにします。

### まとめ
ステップ7とステップ9では、`REPEATABLE-READ`での典型的な状況が発生しました。

## 演習 2：トランザクション隔離レベル - READ-COMMITTED

### 概要
+ この演習では、`READ-COMMITTED` 隔離レベルを体験します。

### 所要時間
+ この演習は約5分程度かかります。

### タスク
1. 2つのデータベースセッションを作成し、システム変数`transaction_isolation`が`READ-COMMITTED`に設定されていることを確認します。
2. アクティブなトランザクションとコミットされたトランザクションからデータを異なるセッションから読み取ろうとしています。

### 手順
1. 両方のターミナルで、システム変数`transaction_isolation`を`READ-COMMITTED`に変更します。
   ```sql
   SET SESSION transaction_isolation='READ-COMMITTED';
   ```
   ```
   Session A> SET SESSION transaction_isolation='READ-COMMITTED';
   --------------
   SET SESSION transaction_isolation='READ-COMMITTED'
   --------------

   Query OK, 0 rows affected (0.01 sec)
   ```
   ```
   Session B> SET SESSION transaction_isolation='READ-COMMITTED';
   --------------
   SET SESSION transaction_isolation='READ-COMMITTED'
   --------------

   Query OK, 0 rows affected (0.01 sec)
   ```

2. セッションAで、新しいトランザクションを開始し、テーブル`test.ilevel`をクエリします。
   ```sql
   BEGIN;
   SELECT * FROM test.ilevel;
   ```
   ```
   Session A> BEGIN;
   --------------
   BEGIN
   --------------

   Query OK, 0 rows affected (0.00 sec)

   Session A> SELECT * FROM test.ilevel;
   --------------
   SELECT * FROM test.ilevel
   --------------

   +----+------------+
   | pk | name |
   +----+------------+
   | 1 | Mars Light |
   | 2 | Sun Light |
   +----+------------+
   2 rows in set (0.00 sec)
   ```

3. セッションB（もう一方のターミナル）に変更し、行番号1のname列を`Mars Light`から`Moon Light`に変更します。
   ```sql
   BEGIN;
   UPDATE test.ilevel SET name='Moon Light' WHERE pk=1;
   COMMIT;
   SELECT * FROM test.ilevel;
   ```
   ```
   ...
   +----+------------+
   | pk | name |
   +----+------------+
   | 1 | Moon Light |
   | 2 | Sun Light |
   +----+------------+
   2 rows in set (0.01 sec)
   ```

4. セッションAに切り替えて、次のクエリを実行して結果を確認します。セッションAは、手順2から開始したアクティブなトランザクションがまだ残っていることに注意します。`READ-COMMITTED` 隔離レベルにより、セッションAはコミットされた（変更された、つまり繰り返し不可能な）データを他のセッションで読み取ることができます。
   ```sql
   SELECT * FROM test.ilevel;
   ```
   ```
   ...
   +----+------------+
   | pk | name |
   +----+------------+
   | 1 | Moon Light |
   | 2 | Sun Light |
   +----+------------+
   2 rows in set (0.00 sec)
   ```

5. 両方のセッションを終了します。

### まとめ
ステップ2とステップ4では、`READ-COMMITTED`での典型的な状況が発生しました。

## 演習終わり