この記事では、トランザクションとは何か、COMMIT と ROLLBACK の違い、そしてデータベースの信頼性を支える ACID特性(原子性・一貫性・分離性・永続性)を、銀行振込の例えとコードでひと通り解説します。
対象は SELECT / UPDATE / INSERT / DELETE は書けるが、トランザクションは聞いたことがない初心者エンジニアです。前回のロックの記事の続編にあたる内容でもあります。
そもそも、なぜトランザクションが必要なのか
銀行の「振込」を例に考えます。AさんからBさんへ1万円を振り込むとき、データベースの中では次の2つの処理が走ります。
- A口座の残高から1万円を引く(UPDATE)
- B口座の残高に1万円を足す(UPDATE)
もし1番目だけ成功して、2番目の直前にシステムが落ちたらどうなるでしょうか。Aさんのお金は減ったのに、Bさんには届いていない──1万円がこの世から消えてしまいます。この2つは「両方成功」か「両方なかったことにする」のどちらかでなければなりません。
この「ひとまとまりの処理を、全部成功か全部取り消しかのどちらかにする」仕組みがトランザクションです。料理のレシピで「材料を全部そろえて作り切るか、何も作らないか」のどちらかにする、というイメージに近いです。
COMMIT と ROLLBACK の基本的な考え方
トランザクションは BEGIN で始まり、処理が問題なく終われば COMMIT で確定、途中で失敗すれば ROLLBACK で開始前の状態に巻き戻します。流れを整理すると次のとおりです。

- BEGIN:トランザクションを開始する
- COMMIT:すべての変更を確定・永続化し、ロックを解放する
- ROLLBACK:すべての変更を取り消して開始前の状態に戻し、ロックを解放する
トランザクションは「全部確定(COMMIT)」か「全部取り消し(ROLLBACK)」かの二択で終わります。中途半端な状態がデータベースに残ることはありません。
トランザクションの基本構文
両方の UPDATE が成功した場合に COMMIT する例です。
BEGIN; -- トランザクション開始
UPDATE account SET balance = balance - 10000 WHERE id = 'A';
UPDATE account SET balance = balance + 10000 WHERE id = 'B';
COMMIT; -- 両方成功 → 確定途中で異常を検知したら、COMMIT の代わりに ROLLBACK を実行します。
BEGIN;
UPDATE account SET balance = balance - 10000 WHERE id = 'A';
-- ここで残高不足などの異常を検知したら…
ROLLBACK; -- Aから引いた分も含めてすべて取り消しCOMMIT とは:「この一連の変更を確定して永続化する」命令です。実行すると変更が正式にディスクへ書き込まれ、障害が起きても消えない状態になり、他のトランザクションからも見えるようになります。前回学んだロックも、このタイミングで解放されます。
ROLLBACK とは:「この一連の変更をすべて取り消して、開始前の状態に戻す」命令です。BEGIN 以降に行った UPDATE や INSERT がなかったことになります。ロックも同様に解放されます。プログラムでは「エラーが起きたら ROLLBACK、問題なければ COMMIT」という形で使うのが基本です。
トランザクションの4つの約束「ACID特性」
トランザクションがデータの信頼性を守るために満たすべき性質を、頭文字を取って ACID特性 と呼びます。難しそうな用語ですが、ひとつずつ見れば素直な内容です。
| 頭文字 | 特性名 | 意味 | 振込の例 |
|---|---|---|---|
| A | Atomicity(原子性) | 全部実行されるか、まったく実行されないか(オール・オア・ナッシング) | 「出金と入金が両方」か「両方なし」。片方だけは起きない |
| C | Consistency(一貫性) | トランザクションの前後で、決められたルール(制約)が常に守られている | 「残高はマイナスにならない」などの制約が破られない |
| I | Isolation(分離性) | 同時に走る別のトランザクションから影響を受けず、互いに邪魔をしない | 他人の振込処理が、自分の振込の途中経過を読んで混乱しない |
| D | Durability(永続性) | 一度 COMMIT した結果は、その後障害が起きても失われない | 振込完了後に停電しても、記録は残っている |
原子性(A)は COMMIT / ROLLBACK で実現され、分離性(I)は前回学んだロックなどで実現されます。つまりロックとトランザクションは別物ではなく、トランザクションの「分離性」を支える部品がロック、という関係です。
分離レベル(応用)
分離性(Isolation)は、実は「どこまで厳密に分離するか」を分離レベルとして段階的に選べます。厳しくするほど安全ですが、待ちが増えて遅くなります。代表的なものは次の4段階です。
| 分離レベル | 概要 |
|---|---|
| READ UNCOMMITTED | 他人の未確定の変更まで見えてしまう(最も緩い) |
| READ COMMITTED | 確定済みの変更だけ見える(多くのDBの既定値) |
| REPEATABLE READ | 同じ行を何度読んでも同じ結果になる |
| SERIALIZABLE | まるで1件ずつ順番に実行したかのように振る舞う(最も厳しい) |
分離レベルが緩いと、「未確定データを読む(ダーティリード)」などの好ましくない現象が起こりえます。初心者のうちは「厳しくするほど安全だが遅くなる、というトレードオフがある」とだけ押さえておけば十分です。
実例:プログラムでの典型的な使い方(Python)
実際のプログラムでは、正常終了したら COMMIT、例外が起きたら ROLLBACK という形で書きます。Python(psycopg2)を使った例です。
conn = psycopg2.connect("dbname=bank")
cur = conn.cursor()
try:
cur.execute("UPDATE account SET balance = balance - 10000 WHERE id = 'A';")
cur.execute("UPDATE account SET balance = balance + 10000 WHERE id = 'B';")
conn.commit() # 両方成功 → 確定
except Exception:
conn.rollback() # 途中で失敗 → すべて取り消し
raise
finally:
conn.close()この形にしておけば、処理の途中で何が起きても「中途半端な状態」が残りません。with 構文やフレームワークの仕組みを使えば、commit / rollback を自動化することもできます。
まとめ
- トランザクションは、ひとまとまりの処理を「全部成功か、全部取り消しか」にする仕組み
- BEGIN で始め、成功なら COMMIT(確定・永続化)、失敗なら ROLLBACK(開始前に巻き戻し)
- 信頼性を支える4つの約束が ACID(原子性・一貫性・分離性・永続性)
- 分離性はロックなどで実現され、分離レベルで安全性と速度のバランスを選べる
最後にひとつ疑問が残ります。「COMMIT した結果が、停電しても消えない(=永続性)」のは、いったいどうやって実現しているのでしょうか。その裏側を支えるのが WAL(先行書き込みログ) です。次回はそのWALと、データベースの内部動作を掘り下げます。
参考リソース
- テックジム「データベーストランザクションのACID特性とは?」 BEGIN / COMMIT / ROLLBACK とACID4特性の初心者向け解説
- Zenn(hogetech)「トランザクションの ACID 特性とは?」 分離レベルとリード現象(ダーティリード等)まで含めた整理
- ビズドットオンライン「ACID特性とは?」 送金例を使った原子性・永続性のわかりやすい説明


コメント