| この記事の要点 |
|
トランザクションとは
トランザクションは「論理的に1つにまとまった複数のSQL文の集合」で、全部成功するか、全部巻き戻すかのどちらかしか起こりません。代表例は銀行振込: 口座A から減算する UPDATE と、口座B に加算する UPDATE は片方だけ成功してはいけません。
基本構文(BEGIN / COMMIT / ROLLBACK)
-- 標準SQL / PostgreSQL
BEGIN; -- または START TRANSACTION
UPDATE accounts SET balance = balance - 1000 WHERE id = 1;
UPDATE accounts SET balance = balance + 1000 WHERE id = 2;
COMMIT; -- 確定(永続化)
-- 失敗時
BEGIN;
UPDATE accounts SET balance = balance - 1000 WHERE id = 1;
-- エラー or 業務ロジックで NG 判明
ROLLBACK; -- 巻き戻し
-- MySQL は START TRANSACTION も BEGIN も同等
START TRANSACTION;
-- ...
COMMIT;
-- SQL Server
BEGIN TRANSACTION;
-- ...
COMMIT TRANSACTION; -- or ROLLBACK TRANSACTION
-- Oracle は明示的な BEGIN 不要(DML 開始時に自動で開始)
UPDATE accounts SET balance = balance - 1000 WHERE id = 1;
COMMIT; -- or ROLLBACK
ACID 特性
| 特性 | 意味 | 保証する仕組み |
|---|---|---|
| Atomicity(原子性) | 全部実行 or 全部巻き戻し | Undo ログ / Rollback Segment |
| Consistency(一貫性) | 制約違反を起こさない状態へ遷移 | 制約検査 / トリガ |
| Isolation(独立性) | 同時実行しても直列実行と同じ結果 | ロック / MVCC |
| Durability(永続性) | COMMIT 後は障害でも残る | REDO ログ / WAL |
SAVEPOINT で部分ロールバック
BEGIN;
INSERT INTO orders(id, user_id) VALUES (1, 100);
SAVEPOINT sp1; -- セーブポイント設定
INSERT INTO order_items(order_id, sku) VALUES (1, 'A');
INSERT INTO order_items(order_id, sku) VALUES (1, 'B');
-- B の挿入に問題発覚
ROLLBACK TO SAVEPOINT sp1; -- sp1 以降だけ巻き戻し
-- INSERT INTO orders は残っている
INSERT INTO order_items(order_id, sku) VALUES (1, 'C');
RELEASE SAVEPOINT sp1; -- 使い終わったら解放
COMMIT;
分離レベル (Isolation Level)
同時実行時に「他のトランザクションの未確定変更がどこまで見えるか」を決めます。
| レベル | Dirty Read | Non-Repeatable | Phantom | 性能 |
|---|---|---|---|---|
| READ UNCOMMITTED | 発生 | 発生 | 発生 | 最速 |
| READ COMMITTED (PG/Oracle 既定) | 防ぐ | 発生 | 発生 | 速い |
| REPEATABLE READ (MySQL 既定) | 防ぐ | 防ぐ | 発生※ | 普通 |
| SERIALIZABLE | 防ぐ | 防ぐ | 防ぐ | 最遅 |
※ MySQL InnoDB の REPEATABLE READ は Gap Lock で Phantom も実質防ぐ。
-- 分離レベルの設定
SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
BEGIN;
-- ...
COMMIT;
-- セッション単位
SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;
-- 現在の分離レベル確認 (MySQL)
SELECT @@transaction_isolation;
-- (PostgreSQL)
SHOW transaction_isolation;
ロックの種類
| ロック | 意味 | 取り方 |
|---|---|---|
| Shared Lock (S) | 読み取り共有。複数同時に取れる | SELECT ... LOCK IN SHARE MODE / FOR SHARE |
| Exclusive Lock (X) | 書き込み排他。他は読み書き不可 | SELECT ... FOR UPDATE / UPDATE/DELETE |
| Intention Lock | 行ロック取得意図のテーブルロック | InnoDB が自動付与 |
| Gap Lock | インデックス範囲の隙間ロック (MySQL) | REPEATABLE READ で自動 |
デッドロック
2つのトランザクションがお互いのロックを待ち続けて進めない状態。DBが検知して片方を強制ロールバックします。
-- トランザクション A
BEGIN;
UPDATE accounts SET balance = balance - 100 WHERE id = 1; -- ロック A
-- ...
UPDATE accounts SET balance = balance + 100 WHERE id = 2; -- B のロック待ち
-- トランザクション B (同時実行)
BEGIN;
UPDATE accounts SET balance = balance - 50 WHERE id = 2; -- ロック B
-- ...
UPDATE accounts SET balance = balance + 50 WHERE id = 1; -- A のロック待ち
-- → デッドロック検知 → どちらかが ERROR 1213 で ROLLBACK
-- 回避策: ロック取得順を統一する(id 昇順で UPDATE)
Autocommit
多くのDBは Autocommit 既定 ON。1つのSQL文ごとに即 COMMIT されます。
-- MySQL: 確認と切替
SELECT @@autocommit; -- 1=ON
SET autocommit = 0; -- OFF。明示的に COMMIT/ROLLBACK 必要
-- PostgreSQL の psql は対話モードでも文ごとに自動 COMMIT
-- BEGIN ... COMMIT で囲めばトランザクション
アプリ側での書き方
Spring (Java) - @Transactional
@Service
public class TransferService {
@Transactional(
isolation = Isolation.READ_COMMITTED,
propagation = Propagation.REQUIRED,
rollbackFor = Exception.class,
timeout = 30
)
public void transfer(long from, long to, BigDecimal amount) {
accountRepo.withdraw(from, amount);
accountRepo.deposit(to, amount);
// 例外が出れば自動 ROLLBACK、正常終了で COMMIT
}
}
Laravel (PHP) - DB::transaction
use Illuminate\Support\Facades\DB;
// クロージャ方式(推奨): 例外で自動ロールバック
DB::transaction(function () use ($from, $to, $amount) {
DB::table('accounts')->where('id', $from)->decrement('balance', $amount);
DB::table('accounts')->where('id', $to)->increment('balance', $amount);
}, 3); // デッドロック時 3 回まで自動リトライ
// 手動方式
DB::beginTransaction();
try {
// ...
DB::commit();
} catch (\Throwable $e) {
DB::rollBack();
throw $e;
}
FAQ
Q: DDL(CREATE TABLE 等)はトランザクションに入る?
A: MySQL/Oracle は DDL で暗黙 COMMIT。PostgreSQL は DDL もトランザクションに含められます。
Q: 分離レベルはどれを選ぶべき?
A: 一般的な業務系は READ COMMITTED で十分。集計や厳密整合性が必要なら REPEATABLE READ / SERIALIZABLE。
Q: COMMIT し忘れたまま接続切断したらどうなる?
A: 自動的に ROLLBACK されます。COMMIT されない変更は他から見えません。
同階層のページ
- DDL
- DML
- トランザクション制御 (SQL)
- データディクショナリ
- 動的パフォーマンスビュー (V$ビュー)
- 関数
人気ページ
- 1 Eclipseで「サーバーに追加または除去できるリソースがありません。」の原因と対処法
- 2 tomcat の起動 / 停止ログと catalina.log・catalina.out の違い
- 3 JavaScript で base URL を取得する方法|window.location.origin
- 4 YouTube Data API v3 エラー一覧|403・400・404 の原因と対処
- 5 Laravel エラー一覧|500/Blade/DB 接続/ルーティングの代表エラー
- 6 3Dグラフィックスとは|モデリング/レンダリング/主要ソフトウェア (Blender / Maya)
- 7 Spring Frameworkのアノテーション一覧
- 8 【Spring】@Valueアノテーションとは
- 9 CATALINA_HOME の確認方法 (Linux / Mac)
- 10 【Spring】@Autowiredアノテーションとは
最近更新/作成されたページ
- MariaDB Monitor (mysql コマンド) の使い方 2026-10-14 15:21:02
- MariaDB の管理ツール (phpMyAdmin / DBeaver 等) 2026-10-14 15:21:02
- Google Custom Search JSON API|新規受付終了・移行期限と既存実装の確認 2026-10-14 14:50:13
- MySQL rootの初期パスワード確認|導入方式・Docker既存DB・復旧の注意 2026-10-14 14:39:34
- MySQL root パスワードの変更方法(ALTER USER / mysqladmin / パスワード忘れ時の復旧) 2026-10-14 14:39:34
- MySQL ALTER USER の使い方|パスワード変更・アカウントロック 2026-10-14 14:39:34
- MySQL ERROR 1129|ホスト遮断の原因・カウンタ・解除前の確認 2026-10-14 14:04:49
- MySQL ERROR 1820・1862|期限切れパスワードの安全な更新と確認 2026-10-14 14:04:49
- MySQL ERROR 1698|ソケット認証・OSユーザー・接続経路の確認 2026-10-14 14:04:49
- mysql_configが見つからない|mysqlclientの旧ビルドとpkg-configの確認 2026-10-14 13:36:32
- MySQLエラー一覧|番号・SQLSTATE別の原因と安全な確認手順 2026-10-14 13:36:32
- インストール直後にNetbeansが反応しない 2026-10-14 13:07:02
- NetBeans でよくあるエラー一覧と対処法 — JDK / Tomcat / PHP / メモリ不足 2026-10-14 13:07:02
- Apache NetBeans入門|起動JDK・プロジェクト作成・関連手順 2026-10-14 13:07:02
- 【Laravel】ページング(ページネーション)をする方法 2026-10-14 12:31:44