コンピューターサイエンス:アルゴリズム / OS / ネットワーク / DB
トランザクションとは
トランザクションとは
このレッスンで分かること
- トランザクションが解決する「途中で失敗する世界」の問題
- BEGIN / COMMIT / ROLLBACK の意味
- SAVEPOINT による部分ロールバック
トランザクション とは
BEGIN / COMMIT / ROLLBACK の意味と必要性を学ぶ。本レッスンでは、トランザクション の基本から実際の使いどころまでを整理し、現場で迷わず使える形に落とし込みます。
銀行送金の例
「Alice の口座から Bob の口座に 1000 円送金する」操作を考えます。アプリ側のコードは次のようになります。
SQL クエリ
UPDATE accounts SET balance = balance - 1000 WHERE name = 'Alice';
UPDATE accounts SET balance = balance + 1000 WHERE name = 'Bob';この 2 文の間で、サーバがクラッシュしたらどうなるでしょうか。Alice の残高は減ったのに、Bob の残高は増えていません。1000 円が宇宙に消失します。これは絶対に許されません。
トランザクションの登場
トランザクション (Transaction) とは、複数の SQL を 「1 つの不可分な単位」 として扱う仕組みです。すべて成功するか、すべて失敗するか、どちらかしかありません。
SQL クエリ
BEGIN;
UPDATE accounts SET balance = balance - 1000 WHERE name = 'Alice';
UPDATE accounts SET balance = balance + 1000 WHERE name = 'Bob';
COMMIT;BEGIN から COMMIT までが 1 つのトランザクションです。途中でクラッシュした場合、DBMS は再起動時に「未コミットの変更」を 全部巻き戻し ます。Alice の残高も Bob の残高も元通り。1000 円は消えません。
3 つの基本コマンド
BEGIN(またはSTART TRANSACTION) — トランザクション開始COMMIT— 変更を確定し、永続化するROLLBACK— 開始以降の変更を全て巻き戻す
COMMIT した時点で初めて、他のセッションから変更が見えるようになります。
SQL クエリ
BEGIN;
INSERT INTO users (name) VALUES ('Carol');
SELECT * FROM users WHERE name = 'Carol'; -- 自分のセッションでは見える
ROLLBACK;
SELECT * FROM users WHERE name = 'Carol'; -- 巻き戻されて見えない自動コミットモード
MySQL も PostgreSQL も、デフォルトでは 自動コミット (autocommit) が有効です。1 文ごとに自動で BEGIN ... COMMIT が走ります。
SQL クエリ
SET autocommit = 0; -- 自動コミット無効化
INSERT INTO ...;
INSERT INTO ...;
COMMIT; -- 明示的にコミットORM やフレームワーク(Rails, Django, Hibernate など)は内部でトランザクションを管理しています。@Transactional、transaction do ... end、with transaction.atomic(): のような記法です。
SAVEPOINT による部分ロールバック
トランザクション内で チェックポイント を作る SAVEPOINT 機能があります。
SQL クエリ
BEGIN;
INSERT INTO orders (...) VALUES (...);
SAVEPOINT after_order;
INSERT INTO order_items (...) VALUES (...);
-- もし失敗したら
ROLLBACK TO SAVEPOINT after_order; -- order は残る
INSERT INTO order_items (...) VALUES (...);
COMMIT;ロングトランザクションの一部だけを取り消すのに便利です。ただし複雑化しやすいので、なるべく短いトランザクションで完結させる方が無難です。
トランザクションの境界の決め方
「どこからどこまでをトランザクションに含めるか」は設計の重要なポイントです。
- 狭く — 整合性を保つ最小単位だけ。短いほどロック競合が減り、性能が良い
- 広く — ビジネス論理の一貫性。一連の処理を 1 つに括る
実務では「1 つのリクエスト = 1 つのトランザクション」が基本パターンです。複数リクエストにまたがる「Saga」のような長期処理は別途設計が必要です。
短いトランザクションは速くて安全。長いトランザクションは事故の元。
デッドロック
複数トランザクションが互いに相手のロックを待つ状態を デッドロック と呼びます。詳細は別レッスンですが、長いトランザクションほどデッドロックを起こしやすいです。
エラーハンドリングの定石
トランザクション内で例外が起きたら必ず ROLLBACK します。アプリ側で try ... catch するのが基本です。
JavaScript
const trx = await db.transaction();
try {
await trx.query("INSERT ...");
await trx.query("UPDATE ...");
await trx.commit();
} catch (err) {
await trx.rollback();
throw err;
}「COMMIT を忘れて ROLLBACK で終わる」のは事故の元です。ORM の自動管理に任せるのが安全です。
やってみよう
- 銀行送金の例を SQLite で再現し、わざと 2 文目を失敗させて
ROLLBACKを実行する - 自動コミットを切って、複数
INSERTを 1 トランザクションでまとめてみる SAVEPOINTを使った部分ロールバックを試す
よくある質問
Q. トランザクションを使うべき場面は?
A. 「複数の更新を全部成功させるか、全部やめるか」が必要な場面で使います。銀行送金(出金と入金)、注文処理(在庫減算と注文記録)、ユーザー登録(複数テーブル更新)などが典型例です。原子性が保たれないと不整合が発生します。
Q. COMMIT と ROLLBACK の使い分けは?
A. 全処理が成功したら COMMIT で確定、途中でエラーが出たら ROLLBACK で全部取り消します。try/catch で囲み、try 末尾で COMMIT、catch 内で ROLLBACK が定型です。例外を握りつぶさず必ず ROLLBACK させる構造を意識しましょう。
Q. トランザクションを長く張ると何が問題ですか?
A. ロックが長時間保持され、他のトランザクションがブロックされて性能が落ちます。MVCC 系 DB では古いバージョンが消えず DB が肥大化します。1 トランザクションは数秒以内に終わるよう、不要な処理(HTTP 呼び出し等)を外に出すのが定石です。
次のレッスン
次は ACID 特性 で、BEGIN / COMMIT / ROLLBACK の意味と必要性を学ぶ を学びます。
事前確認 — 進む前に次の 3 つができることを確認しましょう。
- トランザクションとは の要点を自分の言葉で説明できる
- このレッスンの最小コード (または操作手順) を見ずに書ける
- 練習問題やクイズで間違えた箇所を読み直して理解した
理解度チェック (30 秒)
Q. トランザクションとは とは何か、1 文で説明してください。
A. 本文の「このレッスンで分かること」または冒頭の説明文を見直し、自分の言葉で要約できれば OK。詰まったら本レッスンの最初の H2 セクションを読み返してみましょう。
関連レッスン