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