
2026/02/22 21:28
**データベーストランザクション** は、1 つ以上の SQL 操作(`INSERT`・`UPDATE`・`DELETE`・`SELECT` 等)を含む論理的な処理単位です。 ACID 原則に従います: - **Atomicity(原子性)** – 全ての操作が同時に成功するか、全く適用されません。 - **Consistency(一貫性)** – データベースは有効な状態から別の有効な状態へ遷移します。 - **Isolation(分離性)** – 同時実行されるトランザクション同士が互いに干渉しません。 - **Durability(永続性)** – コミットされた変更はシステム障害後も残ります。 典型的なトランザクションの流れ: ``` BEGIN TRANSACTION -- SQL 文 COMMIT -- 失敗時は ROLLBACK ``` トランザクションにより、マルチユーザー環境でデータ整合性と予測可能な動作が保証されます。
RSS: https://news.ycombinator.com/rss
要約▶
Japanese Translation:
概要
本文では、MySQL と PostgreSQL の 2 つの主要リレーショナルデータベースが、トランザクション、アイソレーションレベル、およびデータ整合性を実装する際に採用している内部メカニズムの違いについて説明しています。両システムとも ANSI の 4 つのアイソレーションレベル(Read Uncommitted, Read Committed, Repeatable Read, Serializable)をサポートしています。
トランザクションの基本
- トランザクションは
で開始し、BEGIN
で終了します。COMMIT; - コミットできない場合は
により、そのトランザクション内で行われたすべての変更が取り消されます。ROLLBACK;
整合性メカニズム
-
PostgreSQL: Multi‑Version Concurrency Control(MVCC)を使用。
- 各行更新は新しいバージョンを作成し、古いバージョンの
と新しいバージョンのxmax
にトランザクション ID を格納して、同時実行セッションでの可視性を決定します。xmin - 廃棄されたバージョンは
により削除されます。VACUUM FULL
- 各行更新は新しいバージョンを作成し、古いバージョンの
-
MySQL: 古い行データを直ちに上書きしつつ、undo log(
列付き)を保持して必要時に以前のバージョンを再構築できるようにします。これによりベーキングが減少します。xid/ptr
競合検出とアイソレーション
- Serializable モードでは PostgreSQL は serializable snapshot isolation と predicate lock を採用し、ブロックせずに競合を検出します。コミット後に競合が検出された場合、トランザクションは中止され再試行する必要があります。
- MySQL は行レベルの共有(S)および排他(X)ロックに依存します。衝突する書き込みはデッドロックを引き起こす可能性があり、エンジンは実行中のトランザクションのいずれかを終了させて解決します。
アイソレーションレベルのトレードオフ
- 高いアイソレーションレベル(例:Serializable)は非反復読取やファントム読取を防ぎます。
- 低いレベル(例:Read Uncommitted)は汚れた読取を許容し、パフォーマンスを向上させます。
これらの違い―トランザクション境界、MVCC vs. undo log、競合処理、および各アイソレーションレベルの意味―を理解することは、開発者が信頼性のあるアプリケーションを設計し、同時実行問題をトラブルシュートし、性能・整合性・スケーラビリティ要件に応じて適切なデータベースシステムを選択する上で不可欠です。
本文
ベン・ディッケン著 | 2026年1月14日
トランザクションは SQL データベースが動作する上での基盤です。毎日数兆ものトランザクションが、SQL データベースに依存した数千のアプリケーションで実行されています。
データベーストランザクションとは?
トランザクションは、データベースに対して一連の操作を「ひとつの原子(atomic)な操作」として実行することです。
1 つのトランザクションには、読み取り・作成・更新・削除など複数の操作が含まれる場合があります。
MySQL と PostgreSQL では、新しいトランザクションを次で開始します。
BEGIN;
そして以下で終了させます。
COMMIT;
この2つのコマンドの間に、検索やデータ操作を行う任意数の SQL クエリを実行できます。
上記例ではトランザクションが開始され、3 つのクエリが実行されたあとコミットされています。コミットは、これらすべての SQL 文で行った変更を原子性付きで適用する行為です。
トランザクションが コミットしない 場合
| 状況 | 説明 |
|---|---|
| 予期せぬ事象(ハードディスク障害、停電など) | MySQL や PostgreSQL は書き込み前ログ(WAL)などの災害復旧技術で対応します。 |
| 故意によるロールバック | トランザクション途中でデータが欠落・不整合だったり、クライアントからキャンセル要求を受けた場合に を実行し、すべての変更を取り消します。 |
上記例では数回の変更後、トランザクションがロールバックされ、その結果データベースは元の状態のままとなります。
トランザクションが重要である理由
複数のクエリが同時に実行されても互いに干渉しないようにします。
同じデータベースへ接続している 2 つのセッションを想定すると:
- セッション A がトランザクションを開始し、データを取得・更新・再取得し、コミットする。
- セッション B はその同じデータをトランザクション内で 2 回取得し、その後両方のトランザクションが完了したあとにもう一度取得する。
- セッション B はセッション A がコミットするまで、
からben
への名前変更を見ることはありません。joe - セッション A がロールバックされた場合、セッション B はそのトランザクションの影響を全く受けません。
これは 一貫した読み取り(consistent reads)を示しています:各トランザクションはコミットされるまで外部からの変更に影響されない隔離されたビューを持ちます。
MySQL と PostgreSQL は REPEATABLE READ モード(それ以上厳格なモード)でこの保証を提供しますが、実装方法は異なります。
| 特徴 | PostgreSQL | MySQL |
|---|---|---|
| 行のバージョニング | / メタデータ付きマルチバージョン行 | Undo ログで古いデータを上書きし、即時に更新 |
| 一貫性メカニズム | トランザクション ID に基づいて適切な行バージョンを読み取る | Undo ログから以前のバージョンを再構築 |
PostgreSQL – 複数行バージョニング
- 各更新ごとに新しい行バージョンが作成され、古いものは残ります。
は作成者トランザクション ID を保持し、xmin
は置換時点を示します。xmax- 未コミットの変更は他トランザクションから見えません。コミット後に全員が新しいデータを見るようになります。
- 時間とともに不要な行バージョンが蓄積し、
コマンドで未使用行を削除しテーブルを圧縮します。VACUUM FULL
MySQL – Undo ログ
- 新しい更新は古いデータを上書きしますが、Undo ログに以前の値を保持します。
- 各行には 2 つのメタデータ列 (
:トランザクション ID、xid
:Undo ログエントリへのポインタ) が存在します。ptr - 別トランザクションが以前のバージョンを必要とするときは Undo ログから読み取ります。
隔離レベル
隔離レベルは、各トランザクションが他者によって変更されたデータをどれだけ見ることができるかを決定します。MySQL と PostgreSQL の両方で 4 つのレベル(強い順)があります。
- Serializable – トランザクションは順序通りに実行されているように振舞います。ロックまたは楽観的衝突解決で実現します。
- Repeatable Read – 非繰り返し読み取りを防止します;MySQL ではファントムリードが起こることがありますが、PostgreSQL では発生しません。
- Read Committed – 非繰り返しおよびファントムリードを許可しつつ、パフォーマンスを向上させます。
- Read Uncommitted – ダーティーリード(未コミットデータが見える)を許容する最も緩いレベルです。
主要な現象
| 現象 | 定義 | 許可されるか |
|---|---|---|
| ファントムリード | 同じ SELECT が別トランザクションのコミット済み挿入により行数が変わる | Repeatable Read 以降で許容 |
| 非繰り返し読み取り | 別トランザクションがコミットした変更により、同一行が異なる値になる | Read Committed 以降で許容 |
| ダーティーリード | 他トランザクションの未コミットデータが見える | Read Uncommitted のみ許容 |
同時書き込み
衝突する書き込みをどう処理するかは、データベースと隔離レベルに依存します。ここでは最も厳格な SERIALIZABLE モードを例示します。
MySQL – 行レベルロック
- 読み取りには共有(S)ロック、書き込みには排他(X)ロックを使用します。
- SERIALIZABLE ではすべての更新が X ロックを取得し、他トランザクションは待機またはデッドロックとなります。 MySQL はデッドロックを検出し、一方のトランザクションを中止します。
PostgreSQL – Serializable Snapshot Isolation
- 行セットに対して predicate lock(例:
)を作成し、使用状況を追跡します。WHERE id BETWEEN 10 AND 20 - 楽観的衝突解決を採用し、トランザクションはブロックされずに実行されますが、SERIALIZABLE 保証に違反する場合は中止されます。
両システムとも最終的には衝突時に一方のトランザクションを停止させるため、重要な操作ではリトライロジックを実装する必要があります。
結論
トランザクションはデータベース設計のほんの一角です。
それらが何であるか、どのように機能し、4 つの隔離レベルが保証するものを理解すれば、より効果的にデータベースを利用できます。
次に取り上げてほしいデータベース管理システムの奥深いテーマは何でしょうか? Discord コミュニティへ参加してぜひ教えてください!
Happy databasing.