🗂

トランザクションのあれこれ

2025/02/04に公開

Daily Blogging45日目

トランザクションを張ることがたまにあるけど、既存コードのコピペしてることが多いので実はちゃんと調べたことない

トランザクションとは

DBMSの機能であり、簡単に言うと

複数のクエリを一貫性のある形でひとまとまりにしたもの

DBMSによってはトランザクションが使えないものがあり、
MySQLだと、2パターンある

  • MyISAM型
    • 利用できない
  • InnoDB型
    • 利用できる

4つの特性

トランザクションは4つの特性で定義されている。
それぞれの頭文字をとってACID特性と呼ばれている

  • Atomicity
    • 「全部成功」か「全部失敗」か
  • Consistency
    • 一貫性
  • Isolation
    • それぞれの処理が矛盾なく行えるか
  • Durability
    • 処理結果を永続化し失われないようにする

ちょっと何言ってるかわかんないですよね

Atomicity

データの変更を伴う一連の操作が必ず二つのうちのいずれかの状態になることを保証する。

  • 全部成功
  • 全部失敗

トランザクションには、「COMMIT」と「ROLLBACK」の二つの概念が存在する。
トランザクションを貼ると、トランザクション内のすべての処理が正常に完了した時点で
「COMMIT」が発行されて、処理の実行結果が確定される。
処理の途中で失敗した場合は、処理の開始前(トランザクション開始時点)まで状態を戻す「ROLLBACK」が発行される。

処理の失敗は、単純なエラーはもちろん、システムダウン時なども「ROLLBACK」が発行される仕組みになっている。

Consistency

トランザクションの前後でDBの整合性がきちんと保たれていることを保証する。
ユニーク制約や外部キー制約など、テーブルに関わるルールにちゃんと則った状態ですよねっていうこと

Isolation

複数のトランザクションが実行されたときに、互いに干渉しないように保証する。
分離には4つのレベルがある

  • READ UNCOMMITTED
    • 他のトランザクションがコミットしていない変更(ダーティリード)を読める
  • READ COMMITTED
    • 他のトランザクションがコミットしたデータのみを読む
    • PostgreSQLとかではこれがデフォルト
  • REPEATABLE READ
    • トランザクションが開始された時点のスナップショットを維持し、同じクエリを実行しても結果が変わらない
    • MySQLはこれがデフォルト
  • SERIALIZABLE
    • 最も厳格な分離レベルで、すべてのトランザクションを直列に実行したかのように扱う
分離レベル 強さ データ整合性 パフォーマンス
READ UNCOMMITTED 🔽 最も低い ❌ 低い ✅ 高い(ロックがほぼ不要)
READ COMMITTED 🔼 やや低い ⭕ 普通 ✅ 高い(更新競合が少ない)
REPEATABLE READ 🔼🔼 中程度 ⭕ 高い 🔽 やや低い(ファントムリードあり)
SERIALIZABLE 🔼🔼🔼 最も高い ⭕ 最も厳格 🔽🔽 低い(ロック競合が増える)

※REPEATABLE READのファントムリードは、PostgreSQLだと防げるようになってる

分離による問題

分離レベルごとに、データの整合性において問題が発生する

  • ダーティリード: コミット前の変更が他のトランザクションから見えてしまう
  • 反復読込不可能: 同じクエリを2回実行したときに結果が変わる
  • ファントムリード: 検索結果のレコード数が途中で増減する
分離レベル ダーティリード 反復読込不可能 ファントムリード
READ UNCOMMITTED ❌ 発生する ❌ 発生する ❌ 発生する
READ COMMITTED ✅ 防げる ❌ 発生する ❌ 発生する
REPEATABLE READ ✅ 防げる ✅ 防げる ❌ 発生する
SERIALIZABLE ✅ 防げる ✅ 防げる ✅ 防げる

Durability

トランザクションがコミットされた後は、システムがクラッシュしてもデータが失われないことを保証する。
システム障害時のためであり、DBのパフォーマンス向上にもつながる。

トランザクションが完了したらその結果がDBにすぐに書き込まれるわけじゃない
→ハードディスクへの書き込みは遅いので、同期的に書き込んでたらパフォーマンスが悪くなる

そのため、トランザクションが完了したらディスクへデータを書き込む前に、ログに書き込んだりしてトランザクションの記録を残したりしている。
→WAL (Write-Ahead Logging)

Discussion