トランザクション
Transaction
概要(サマリー)
トランザクション(Transaction)とは、データベースで複数の処理を1つのまとまりとして扱い、成功したら確定し、失敗したら元に戻す仕組みである。
たとえば銀行振込では、「Aさんの口座からお金を引く」と「Bさんの口座にお金を足す」がセットで成功しなければならない。片方だけ成功すると、お金が消えたり、増えたりしたような矛盾が起きてしまう。
トランザクションは、このような「途中まで成功した状態」を残さないための安全装置である。すべての処理が問題なく終わったら確定し、どこかで失敗したらロールバックして、処理前の状態に戻す。
詳細解説
トランザクションとは何か
データベースを使うシステムでは、1つの操作に見えても、裏側では複数の更新が行われることが多い。注文処理なら、注文データを保存し、在庫数を減らし、決済記録を残す、といった処理が組み合わさる。
このような処理の途中でエラーが起きると、注文データだけ作られて在庫が減っていない、決済だけ終わって注文が作られていない、といった不整合が起きる。トランザクションは、複数の処理を「ひとかたまり」として扱い、中途半端な状態を残さないようにする。
初心者向けには、「複数の作業をまとめて封筒に入れ、全部そろったら提出し、問題があれば封筒ごと破棄する仕組み」と考えるとわかりやすい。
COMMITとROLLBACK
トランザクションでは、処理を始めたあとに、最終的に「確定する」か「取り消す」かを決める。
COMMITは、トランザクション内で行った変更を正式にデータベースへ反映する操作である。ROLLBACKは、トランザクション内で行った未確定の変更を取り消し、処理前の状態に戻す操作である。
つまり、トランザクションは「箱」であり、コミットとロールバックはその箱の中身をどう扱うかを決める操作である。ロールバックはトランザクションそのものではなく、トランザクションの中で使われる取り消し操作だと整理すると混同しにくい。
基本的なSQLの例
以下は、Aさんの口座からBさんの口座へ1万円を移す処理を単純化したSQLの例である。
START TRANSACTION;
UPDATE bank_accounts
SET balance = balance - 10000
WHERE user_id = 'A';
UPDATE bank_accounts
SET balance = balance + 10000
WHERE user_id = 'B';
COMMIT;
この例では、2つの UPDATE が両方とも成功した場合に COMMIT で確定する。もし途中でエラーが起きた場合は、プログラム側で例外を検知し、次のように取り消す。
ROLLBACK;
実際のアプリケーションでは、SQLを直接書く場合だけでなく、ORMのトランザクション機能を使って同じ考え方を実装することも多い。
ACID特性
トランザクションの信頼性を説明するときによく出てくるのが、ACID特性である。ACIDは、Atomicity、Consistency、Isolation、Durabilityの頭文字を取った言葉である。
- Atomicity(原子性): トランザクション内の処理が、すべて成功するか、すべて取り消されるかのどちらかになる性質。
- Consistency(一貫性): トランザクションの前後で、制約やルールに反する矛盾した状態を残さない性質。
- Isolation(隔離性): 同時に複数のトランザクションが動いても、未確定の途中経過が他の処理に不用意に見えないようにする性質。
- Durability(永続性): 確定された変更が、障害後にも失われにくいように保存される性質。
ただし、隔離性や永続性の細かい挙動は、データベース製品、設定、ストレージ、分離レベルによって変わる。初心者の段階では、まず「中途半端な更新を残さないための考え方」として理解するとよい。
トランザクションが必要になる場面
トランザクションは、複数のデータ更新をセットで扱う場面で特に重要である。
- ECサイトで、注文作成、在庫減少、決済記録をまとめて扱う。
- 予約システムで、座席確保と予約情報の作成をまとめて扱う。
- ポイント機能で、ポイント利用履歴と残高変更をまとめて扱う。
- 管理画面で、親データと子データを同時に保存する。
反対に、単純な読み取り処理や、失敗してもデータの整合性に影響しにくい処理では、明示的なトランザクションを意識しないこともある。何でもかんでも長いトランザクションで囲めばよいわけではなく、「途中で止まると困る更新処理」に使うのが基本である。
使うときの注意点
トランザクションは便利だが、万能ではない。長時間開いたままにすると、他の更新処理が待たされたり、ロック競合が起きたりすることがある。
そのため、トランザクションの中では、必要なデータベース更新を短くまとめるのが基本である。外部APIへの通信、重いファイル処理、ユーザー入力待ちのような時間の読みにくい処理を、トランザクション内に長く置かない設計が望ましい。
また、エラーが起きたときに自動でロールバックされるか、明示的にロールバックを書く必要があるかは、使っているライブラリやフレームワークによって異なる。MySQL、PostgreSQL、ORM、フレームワークの公式ドキュメントを確認することが大切である。
AIコーディングとの関係
AIにデータベース更新処理を書いてもらうとき、トランザクションは明示的に指示したほうがよい重要ポイントである。「注文作成APIを書いて」だけでは、AIが注文データの作成と在庫更新を別々に書いてしまうことがある。
たとえば、次のように指示すると、AIが安全な設計を考えやすくなる。
- 注文データの作成、在庫数の更新、決済記録の保存を1つのトランザクションで実行してください。
- 途中でエラーが起きた場合は、すべての変更がロールバックされるようにしてください。
- 使用しているORMのトランザクション機能を使い、例外処理も含めて書いてください。
- トランザクション内で外部APIを長時間待たない構成にしてください。
AIが生成したコードを見るときは、「複数の更新処理が同じトランザクションに入っているか」「エラー時の扱いが明確か」「リトライしても二重登録にならないか」を確認するとよい。トランザクションは、AIが書いたコードを安全に実務へ近づけるためのレビュー観点にもなる。
よくある勘違い
トランザクションを使えばエラーが自動で直る?
トランザクションは、エラーで中途半端なデータが残るのを防ぐ仕組みである。プログラムのバグを直したり、通信障害を自動で解決したりするものではない。
ロールバック後にユーザーへエラーメッセージを出す、再試行できるようにする、管理者へ通知する、といった処理は別途実装する必要がある。
ロールバックとトランザクションは同じ?
同じではない。トランザクションは複数の処理をまとめる仕組みで、ロールバックはその中で未確定の変更を取り消す操作である。
「トランザクションを開始する」「コミットする」「ロールバックする」という流れで覚えると整理しやすい。
トランザクション中は他のユーザーが必ず何もできなくなる?
トランザクション中でも、他のユーザーのすべての操作が止まるわけではない。多くのデータベースでは、未確定の変更を他の処理から見えにくくしたり、必要な範囲だけをロックしたりして整合性を守る。
ただし、同じデータを同時に更新しようとすると、一方が待たされたり、デッドロックが起きたりする場合がある。そのため、トランザクションは短く保つことが大切である。
読み取り処理にも毎回トランザクションが必要?
すべての読み取り処理で、開発者が明示的にトランザクションを書く必要があるとは限らない。データベースやライブラリによっては、1つのSQL文が暗黙的にトランザクションとして扱われることもある。
一方で、複数の読み取り結果を一貫した時点のデータとして扱いたい場合など、読み取り中心でもトランザクションが意味を持つ場面はある。重要なのは、目的に合わせて使い分けることである。
まとめ
- トランザクションは、複数のデータベース処理を1つのまとまりとして扱う仕組みである。
- 成功時は
COMMITで確定し、失敗時はROLLBACKで未確定の変更を取り消す。 - ACID特性は、トランザクションの信頼性を説明する基本的な考え方である。
- 注文、決済、予約、在庫更新など、途中で止まると困る処理で特に重要になる。
- AIにデータ更新コードを生成させるときは、トランザクションとエラー処理を明示して依頼するとよい。
情報ソース
- PostgreSQL Documentation: Transactions
- MySQL 8.4 Reference Manual: START TRANSACTION, COMMIT, and ROLLBACK Statements
より詳しくAIに聞いてみよう
- データベースのトランザクションを、銀行振込の例で初心者向けに説明してください。
- トランザクションのACID特性を、それぞれ具体例つきで説明してください。
- トランザクションとロールバックの違いを、実装例を交えて整理してください。
- ORMでトランザクションを使うときの基本パターンを、初心者向けに教えてください。
- AIに注文処理や決済処理のコードを生成してもらうとき、トランザクションについてどのように指示すればよいですか。