【MySQL】同一トランザクションの実行結果は次の処理にも反映される


1つのトランザクションの中でINSERT、SELECTを連続で実行したところ、先にINSERTしたCOMMITされていないレコードも取得できました。

なぜ取得できるのか分からなかったので調査・検証してみました。

検証

SQLを実行

トランザクション前のテーブルの状態です。

mysql> SELECT * FROM animals;
+----+------+
| id | name |
+----+------+
|  1 | dog  |
+----+------+
1 row in set (0.00 sec)

トランザクション開始

トランザクション分離レベルはデフォルトのREPEATABLE-READです。

mysql> START TRANSACTION;
Query OK, 0 rows affected (0.00 sec)

INSERT実行

mysql> INSERT INTO animals (name) VALUES ('cat');
Query OK, 1 row affected (0.00 sec)

SELECT実行

まだCOMMITされていませんが、先ほどINSERTしたcatが取得できます。

mysql> SELECT * FROM animals;
+----+------+
| id | name |
+----+------+
|  1 | dog  |
|  2 | cat  |
+----+------+
2 rows in set (0.00 sec)

トランザクション分離レベルを変更して実行

他のトランザクション分離レベルに変更して検証しましたが、結果は同じでした。

  • READ COMMITTED
  • READ UNCOMMITTED
  • SERIALIZABLE

トランザクション分離レベルの変更方法

現在のトランザクション分離レベルを確認します。
MySQL トランザクション分離レベルを確認する方法

-- 8系はSELECT @@transaction_isolation;
mysql> SELECT @@tx_isolation;
+-----------------+
| @@tx_isolation  |
+-----------------+
| REPEATABLE-READ |
+-----------------+
1 row in set, 1 warning (0.00 sec)

トランザクション分離レベルを変更します。グローバルではなくセッションのみ適用します。
MySQL公式マニュアル: SET TRANSACTION 構文

-- READ COMMITTEDに変更
mysql> SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
Query OK, 0 rows affected (0.01 sec)

まとめ

調べても根拠となる資料は見つかりませんでしたが、とあるサイトに同様の質問が投稿されていました。
【DB】同じトランザクション内でupdateとselectをしたときの結果値

トランザクションというのはそういうものだからとしかいいようがないかと。
トランザクション内でupdateしたものが一時的に反映されないなら
updateされたことを前提に行うその後の処理が無意味になりますよね

確かに。分離レベル以前の問題でした。

ついでにトランザクション分離レベルについても調べました。こちらの記事が検証手順も詳細で分かりやすかったです。
トランザクション分離レベルについてのまとめ

採用PR

弊社で一緒に働く仲間を募集しています。
全てのオタクを幸せにしたい方、是非ご覧ください!