コンピューターサイエンス:アルゴリズム / OS / ネットワーク / DB

トランザクションとは

生田 陸人
LuaGate エンジニア / 現役エンジニア
編集 LuaGate編集部

トランザクションとは

このレッスンで分かること

  • トランザクションが解決する「途中で失敗する世界」の問題
  • 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 円は消えません。

diagram (will load when visible)

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 など)は内部でトランザクションを管理しています。@Transactionaltransaction do ... endwith 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 つができることを確認しましょう。

  1. トランザクションとは の要点を自分の言葉で説明できる
  2. このレッスンの最小コード (または操作手順) を見ずに書ける
  3. 練習問題やクイズで間違えた箇所を読み直して理解した

理解度チェック (30 秒)

Q. トランザクションとは とは何か、1 文で説明してください。

この章のポイント

A. 本文の「このレッスンで分かること」または冒頭の説明文を見直し、自分の言葉で要約できれば OK。詰まったら本レッスンの最初の H2 セクションを読み返してみましょう。

関連レッスン