データベース

トランザクションとは?ACID・分離レベル・commit/rollbackを実装目線で解説【2026年版】

トランザクションは、複数のデータベース操作を「全部成功」か「全部なかったことにする」かのどちらかにまとめる仕組みです。銀行の口座振替で片方の残高だけが減る事故を防ぐのが役割で、その安全性を支えるのがACID特性です。この記事では、commitとrollbackの基本動作から、READ COMMITTEDなど分離レベル4種と並行処理で起きる読み取り異常、共有ロックと排他ロックによる排他制御、そしてアプリ側のトランザクション境界の設計判断や分散トランザクションの選び方まで、業務システムを実装・選定する立場で整理します。DB製品ごとにデフォルトの挙動が違う点も具体的に押さえます。

目次

まとめ:トランザクションの定義と実装で押さえる判断の要点

トランザクションとは、分けられない1つの処理単位として複数の操作をまとめ、成功時にcommitで確定し、失敗時にrollbackで開始前の状態へ戻す仕組みです。この「全か無か」を保証する性質がACID特性のA(原子性)で、残る一貫性・分離性・永続性と合わせてデータの信頼性を支えます。

実装で判断が分かれるのは分離レベルの選択です。既定でどこまで並行処理を許すかはDB製品によって異なり、PostgreSQLは READ COMMITTED、MySQLのInnoDBは REPEATABLE READ が初期値です(いずれも2026年時点の系列)。緩い分離レベルはダーティリードなどの読み取り異常と引き換えに速度を稼ぎ、SERIALIZABLEは異常を消す代わりにロック競合とやり直しが増えます。

結論として、実務ではまず「トランザクションを短く保つ」ことを最優先に設計します。ユーザーの入力待ちを挟んだ長時間トランザクション、1件ずつcommitするループ、外部API呼び出しをトランザクション内に閉じ込める作りは、ロック保持とデッドロックの主因になるため、ここでは避けるべき作りです。整合性が金銭や在庫に直結する基幹システムでは、この境界設計を最初から誤らないことが後戻りコストを抑える鍵になります。

トランザクションの定義とcommit・rollbackの基本動作

トランザクションは、データベースに対する一連の読み書きを「これ以上分割できない1単位」として扱う概念です。単位の途中で処理が止まっても中途半端な状態を残さない、という約束がすべての出発点になります。

口座振替の具体例で理解するトランザクションの原子的な処理単位

A口座からB口座へ1万円を移す処理は、「Aから1万円引く」「Bへ1万円足す」という2つの更新から成ります。片方だけが実行されて障害で止まると、1万円が消えるか二重になる事故です。この2操作を1つのトランザクションにまとめると、両方成功して初めて結果が残り、途中で失敗すれば両方が取り消されます。

この「全部やる、さもなくば何もしない」という単位化が、トランザクションの本質です。1件の更新に見える処理でも、裏でインデックス更新やトリガが走るなら、それらもまとめて1単位として扱われます。トランザクションを管理する主体はDBMS本体であり、その全体像はDBMSとは?機能・種類・RDBMS製品の選び方で整理しています。

BEGIN・COMMIT・ROLLBACKで区切るトランザクションの明示的な境界

SQLでは、トランザクションの開始をBEGIN(またはSTART TRANSACTION)で宣言し、確定をCOMMIT、取り消しをROLLBACKで指示します。commitした時点で結果がディスクに永続化され、他の利用者からも見えるようになります。

明示的にBEGINを書かない単発のSQLは、多くのRDBMSで「自動コミット(autocommit)」として1文ごとに即座に確定します。複数文をまとめたいときだけ境界を自分で宣言する、という使い分けです。長い処理の途中に戻り先を作るSAVEPOINTを置けば、トランザクション全体ではなく一部だけをrollbackすることもできます。COMMITやROLLBACKがどの文の種類にあたるかはSQLとは?文の種類と実行順序で扱う制御文(TCL)に位置づけられます。

ACID特性が支えるデータ整合性とトランザクション処理の信頼性

ACIDは、トランザクションが満たすべき4つの性質の頭文字です。原子性(Atomicity)、一貫性(Consistency)、分離性(Isolation)、永続性(Durability)を指し、これらが揃って初めて「データベースを信頼して業務を載せられる」状態になります。

原子性・一貫性・分離性・永続性というACIDの4つの構成要素

それぞれの性質が守るものは次のとおりです。実務では、原子性と永続性は多くのRDBMSが標準で守り、分離性だけが後述の分離レベルで調整可能、と押さえると全体像がつかめます。

特性 保証する内容 破れたときの例
原子性 全実行か全取消 振替で片方だけ更新
一貫性 制約を常に満たす 残高がマイナス値に
分離性 同時実行が干渉しない 未確定データを他が参照
永続性 commit後は消えない 停電で確定分が消失

一貫性は、原子性・分離性・永続性とアプリ側の制約定義が守られた結果として保たれる性質で、単独の仕組みというより他の3つの帰結にあたります。外部キーやCHECK制約をDB側に置くほど、この一貫性をアプリの実装ミスから守れます。

WALによるログ先行書き込みがcommit後の永続性を担保する仕組み

永続性は、commitしたデータが障害後も残ることを指します。多くのRDBMSは、データ本体を更新する前に変更内容をログへ先に書く「WAL(Write-Ahead Logging)」でこれを実現する仕組みです。ログさえディスクに残っていれば、クラッシュ後の再起動時にログを再適用して確定済みの結果を復元できます。

この仕組みは、commit時にログの書き込み完了を待つため、ディスクI/Oの速さが応答時間を左右します。大量の小さなトランザクションを高頻度でさばくOLTP(オンライントランザクション処理)では、この書き込みがボトルネックになりやすく、処理方式の特徴はOLTPとは何か?基本定義で解説しています。

トランザクション分離レベル4種と並行処理で生じる読み取り異常

複数のトランザクションが同時に走ると、片方の未確定・途中の変更をもう片方が見てしまう「読み取り異常」が起こり得ます。どこまで許容するかを段階で定義したものが分離レベルです。標準SQLは4段階を規定します。

ダーティリード・ノンリピータブルリード・ファントムの3つの異常

分離が緩いほど発生し得る異常が増えます。代表的な3つの異常は次のように区別します。

  • ダーティリード:他のトランザクションが未commitの変更を読んでしまう。相手がrollbackすれば、存在しない値を読んだことになる。
  • ノンリピータブルリード:同じ行を2回読むと、間に他がcommitした更新で値が変わっている。
  • ファントムリード:同じ条件で検索すると、間に他が挿入した行が2回目に増えている。

ダーティリードは金額の集計などで致命的になりやすく、実務で許容する場面はほとんどありません。ノンリピータブルとファントムは、同一トランザクション内で繰り返し集計する処理でだけ問題になります。

標準SQLの4つの分離レベルと各段階で許容される読み取り異常

分離レベルと、その段階で起こり得る異常の関係を整理します。下に行くほど厳格になり、異常は消えますが並行性は落ちます。

分離レベル ダーティ ノンリピータブル ファントム
READ UNCOMMITTED 起こる 起こる 起こる
READ COMMITTED 防ぐ 起こる 起こる
REPEATABLE READ 防ぐ 防ぐ 製品による
SERIALIZABLE 防ぐ 防ぐ 防ぐ

ファントムの扱いは製品差が大きく、MySQLのInnoDBは REPEATABLE READ でもネクストキーロックによりファントムをほぼ抑えます。分離レベルはSET TRANSACTION ISOLATION LEVELで切り替えられますが、既定値のまま運用するケースが大半です。

PostgreSQL・MySQL・OracleでのデフォルトDB分離レベルの差

同じSQLでも、DB製品のデフォルト分離レベルが違うと挙動が変わります。移行やマルチDB構成で見落とすと不具合の原因になります(いずれも2026年時点の主要系列の既定値)。

製品 既定の分離レベル 特徴
PostgreSQL READ COMMITTED MVCCで読取を非ブロック
MySQL(InnoDB) REPEATABLE READ ネクストキーロック採用
Oracle READ COMMITTED SERIALIZABLE選択可

PostgreSQLとOracleは既定でノンリピータブルリードが起こり得るのに対し、MySQLは既定でそこまで防ぎます。「開発環境のMySQLでは再現しないのに本番のPostgreSQLで整合性がずれる」といった事象は、この既定値の差が原因のことがあります。製品ごとの前提差はMySQLとは?特徴とバージョン選定も参照してください。

排他制御とロックの基本の仕組みと共有ロック・排他ロックの違い

分離性を実現する土台が排他制御です。同じデータへの同時アクセスを、ロックによって順番待ちさせたり、読み取り専用の複製を見せたりして干渉を防ぎます。ロックの粒度と種類を理解すると、性能と整合性のトレードオフが見えてきます。

共有ロックと排他ロックの両立可否と行・テーブル単位のロック粒度

ロックには大きく2種類あります。読み取り用の共有ロックは複数のトランザクションが同時に取得でき、書き込み用の排他ロックは1つしか取得できず、共有ロックとも両立しません。この非両立の関係が「読んでいる間は書けない、書いている間は読めない」を生みます。

ロックをかける単位(粒度)は、行・ページ・テーブルと段階があります。行ロックは並行性が高い一方でロック管理のコストがかかり、テーブルロックは単純ですが同時実行を大きく制限する特性です。1件ずつ狙って更新するなら行ロック、集計や一括洗い替えならテーブル単位、という使い分けになります。

競合頻度で判断する楽観ロックと悲観ロックの使い分けと回避方針

アプリ側の設計判断として、ロックをかけてから更新する悲観ロックと、更新直前にバージョンの不一致を検出する楽観ロックがあります。競合が稀な画面編集では楽観ロック、在庫引き当てのように競合が前提の処理では悲観ロックが向く、という住み分けです。両者の実装差はDB別に楽観ロックと悲観ロックとは?違い・使い分けで詳述しています。

複数のトランザクションが互いのロック解放を待ち合って進めなくなる状態がデッドロックです。更新するテーブルやレコードの順序をアプリ全体で揃えるだけで、多くのデッドロックは避けられます。検出と解消の具体策はデッドロックとは?原因・検出・予防策で扱っています。

トランザクション境界の設計判断と実装で避けたいアンチパターン

トランザクションの正しさは、ACIDの理解よりも「どこから始めてどこで終えるか」という境界設計で決まります。ここでは、実装現場で繰り返し見かける失敗と、その回避の判断基準を言い切ります。

長時間トランザクションと外部API呼び出しを境界に含めない設計

最も避けるべきは、ユーザーの確認待ちや外部APIの応答待ちをトランザクションの内側に入れることです。ロックを保持したまま人間や外部システムを待つことになり、その間ほかの処理が止まり、タイムアウトやデッドロックを誘発します。

判断基準はシンプルです。トランザクションはミリ秒〜数百ミリ秒で閉じることを目標にし、外部API呼び出しは境界の外に出します。決済APIのように外部呼び出しと整合を取りたい場合は、いったんローカルに「処理中」状態を確定させ、外部応答は別トランザクションで反映する二段構えにします。ここを守れないなら、その処理は1つのトランザクションで完結させるべきではありません。

1件ずつcommitするループと一括処理の速度と安全のトレードオフ

大量データを1件ずつBEGIN・COMMITするループは、commitごとにWALの書き込み待ちが発生し、処理が桁違いに遅くなります。一方で数十万件を1トランザクションにまとめると、ロック保持が長くなり、失敗時のrollbackも重くなります。

実務での落としどころは、数百〜数千件ごとにcommitする「バッチコミット」です。この単位なら書き込み回数を抑えつつ、ロック保持時間とrollbackの範囲も限定できます。件数の適切な区切りは行サイズとロック競合の度合いで変わるため、本番相当のデータ量で計測して決めるのが確実です。データ更新の実行単位そのものの考え方はクエリとは?実行の仕組みと高速化も参考になります。

基幹システムで整合性要件からトランザクション設計を逆算する判断

会計・受発注・在庫のような基幹システムでは、「どのデータが同時に正しくなければ業務が破綻するか」を先に定義し、その単位をトランザクション境界にします。逆に、通知の送信やログの記録のように多少ずれても業務が壊れないものは、あえて境界の外に出して本体の処理を軽くします。

この逆算を誤ると、後からロック競合や不整合が頻発し、作り直しに大きなコストが生じかねません。整合性要件が金銭や在庫に直結する基幹システムの設計・開発では、この境界の見極めが品質を左右する分かれ目になります。要件からのDB設計と実装を外部に相談する場合は、基幹システム開発の受託で承っています。

分散トランザクションで2相コミットとSagaパターンを選ぶ基準

マイクロサービスや複数DBにまたがる処理では、1つのトランザクションで全体を確定できません。複数のリソースをまとめて整合させる仕組みが分散トランザクションで、代表的な2つの手法をどう選ぶかを整理します。

2相コミットの準備・コミット2フェーズの仕組みと同期整合の限界

2相コミット(2PC)は、調整役が全参加者に「準備できたか」を問い(準備フェーズ)、全員がOKなら「確定せよ」と指示する(コミットフェーズ)方式です。全リソースを同期的に整合させられる反面、準備完了後に調整役が落ちると参加者がロックを抱えたまま宙づりになるブロッキング問題を抱えます。

この特性から、2PCはネットワークが安定し参加者が少ない構成、例えば同一データセンター内の複数DBをまとめる場面に向きます。サービス数が多くネットワーク遅延が読めないマイクロサービスでは、待ち時間と障害時のリスクが見合わなくなります。

Sagaパターンと補償トランザクションによる結果整合性の実現

Sagaは、処理を複数のローカルトランザクションに分割し、途中で失敗したら「補償トランザクション」で前の処理を打ち消していく方式です。全体を一瞬で整合させる代わりに、最終的に整合する「結果整合性」を受け入れます。ロックを長く持たないためスケールしやすい一方、補償ロジックを1ステップごとに自前で設計する負担が生じます。

単一DBで完結させる選択肢も含めた分散処理の採否を分ける基準

ここは判断を言い切ります。分散トランザクションは、可能な限り採用しないのが最善です。サービスを分けたい理由が組織や規模の都合であって整合性要件でないなら、まず同一DB内のトランザクションで完結する設計に寄せます。単一DBで足りるなら、2PCもSagaも要りません。

それでも分散が避けられない場合は、強い整合が必須で参加者が少数なら2PC、参加者が多くスケールと可用性を優先するならSaga、と切り分けます。「なんとなくマイクロサービスだから2PC」という選び方は、ブロッキングと運用の複雑さを持ち込むだけなので採用しません。

よくある質問

トランザクションの実装でつまずきやすい点を、検索されやすい疑問の形で補足します。

トランザクションとロックの違いは何ですか?

トランザクションは「複数操作を1単位にまとめ、全か無かで確定する」という論理的な枠組みです。ロックは、その分離性を実現するための下位の仕組みで、同じデータへの同時アクセスを順番待ちさせる技術です。トランザクションが目的、ロックがそれを支える手段という関係になります。

commitとrollbackはいつ実行すればよいですか?

一連の更新がすべて成功し、業務として整合が取れた時点でcommitします。途中で例外が発生したり、業務ルールに反する状態が見つかった場合はrollbackして開始前に戻します。アプリのフレームワークでは、処理が正常終了したら自動commit、例外送出時に自動rollbackする形が一般的です。

分離レベルは変更したほうがよいですか?

多くのケースでは既定値のままで問題ありません。変更を検討するのは、同一トランザクション内で同じ集計を複数回行い結果を揃えたい場合(より厳格へ)や、参照専用で速度を優先したい場合(より緩やかへ)に限られます。既定値はDB製品で異なるため、まず自分の使うDBの既定を確認します。

autocommitはオフにすべきですか?

単発の更新しか行わないなら、autocommitのままで支障ありません。複数の更新を1単位にまとめたい処理でだけ、明示的にBEGINで境界を宣言します。多くのORMやフレームワークは、トランザクションブロックの内側で自動的にautocommitを無効化するため、通常は個別に切り替える必要はありません。

NoSQLにトランザクションはありますか?

製品による、というのが実情です。かつてはNoSQLはトランザクション非対応とされましたが、現在はドキュメントDBの複数ドキュメント更新など、複数操作にまたがるトランザクションを備える製品が増えています。ただしRDBMSほど強い保証を全機能で提供するとは限らないため、採用時は対象操作の保証範囲を製品ドキュメントで確認します。

関連記事

資料請求

RELATED POSTS 関連記事