8
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

[小ネタ] MySQL (InnoDB) でユニットテスト最中のDBを外部から見たい場合は READ UNCOMMITTED を使うといいかも

Last updated at Posted at 2025-02-05

はじめに

この記事は MySQL 8.0.26 をベースに記述しています

みなさんDBを使ったユニットテストをしていますか?

最近では少なくない「状況が許すならユニットテストでもモック・スタブじゃなくてリアルDB使えばいいじゃん」派の方は、DBを使ったユニットテストについて、以下のようなコードを書いていると思うのですが、たまにユニットテスト最中のDBを見たくなると思います。

try {
  db.begin();

  // テスト用データの準備
  db.exec(`DELETE FROM test`);
  db.exec(`INSERT INTO test VALUES (....)`)
  
  testedMethod(); // ← ここをデバッグ実行とかで止めながらDBのデータをじっくり見たい!!

  // データの検証
  ...
} finally {
  // ユニットテスト中にいじったデータのロールバック
  db.rollback();
}

もちろんユニットテストによるDB変更は最後にロールバックされるので、ユニットテスト中のDBの内容を見ようがありません。ロールバックのコードを一時的に取り除いたりで見ることはできますが、面倒な上にユニットテストで既存データが破壊されるので困りものです。

(まあそもそも品のいいエンジニアリングをしている人達はあまりこういうことをしたいとはならないのでしょうが……)

(MySQLの場合) そこで READ UNCOMMITTED !

そういう時は READ UNCOMMITTED 分離レベルで繋ぎましょう。他のトランザクション(ユニットテスト)による変更をある程度見ることができます。

例えば以下はDBeaverによる分離レベルの設定画面です。 1

image.png

ユニットテスト接続の変更を見る際は、次のような流れになります。 ダーティーリード の部分が今回の狙いです。

MySQL 8.0.26 で上記の動きを確認済みですが、将来のバージョンでダーティーリードが排除されたとしても不思議ではないし、トランザクション内容によってはダーティーリードが予想可能な形で発生するとは言えないので、あくまで現時点で通じるデバッグツールの一種ぐらいと捉えたほうが良さそうです。

(おまけ) MySQL (InnoDB) のトランザクション分離レベルについて

  • REPEATABLE READ: デフォルト。トランザクション中に見える内容が基本的に他者起因で変わらない
  • READ COMMITTED: トランザクション中に他でコミットされた内容が見える
  • READ UNCOMMITTED: トランザクション中に他でコミットされていない内容も見える(ダーティーリード)。本記事で使っている分離レベル
  • SERIALIZABLE: 見た行全部ロック

詳しくは以下を参照してください。

PostgreSQLの場合はどうなのか?

PostgreSQLでは READ UNCOMMITTEDREAD COMMITTED のように振る舞います。よってこの手法は使えません。残念!

PostgreSQL's Read Uncommitted mode behaves like Read Committed. This is because it is the only sensible way to map the standard isolation levels to PostgreSQL's multiversion concurrency control architecture.

まとめ

MySQLで READ UNCOMMITTED 分離レベルを使うと別トランザクションの変更を見ることができます。ユニットテスト中の最終的にロールバックされるデータベース変更を眺めるには便利なこともあるでしょう。

ちなみにPostgreSQLでも通用するようなユニットテスト中のトランザクションを覗く方法となると、ユニットテストのためだけのDBを専用で立てておき、データがユニットテストでいかに壊されようと問題がない状況とし、細かくユニットテスト中にコミットのコードを入れるぐらいしか方法が無いと思います。コード中で獲得しているデータベースコネクションを他ツールに分配するようなことができればいいのですがそのような方法は見つかりませんでした……

  1. DBeaver の分離レベルのオプションは一度テスト接続しないと表示されないことに注意しましょう(空欄しか出なくてびっくりすると思うので)

8
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?