この内容は古いバージョンです。最新バージョンを表示するには、戻るボタンを押してください。
バージョン:5
ページ更新者:guest
更新日時:2026-06-11 07:07:02

タイトル: COMMIT (トランザクション制御)
SEOタイトル: SQL COMMIT 文 完全ガイド(暗黙コミット / Two-Phase Commit / 言語別 commit())

この記事の要点
  • COMMIT はトランザクション内の変更を確定し永続化する命令
  • COMMIT / COMMIT TRANSACTION / COMMIT WORK は同義(DB方言)
  • DDL (CREATE/ALTER/DROP) は多くのDBで暗黙COMMITを引き起こす
  • 分散トランザクションは Two-Phase Commit (XA): PREPARE → COMMIT
  • SET AUTOCOMMIT=0 で明示COMMIT モード。アプリ実行前のセオリー

COMMIT とは

COMMIT はトランザクション中に行った変更をDBに永続化し、他のセッションから見えるようにする命令です。COMMIT 前の変更は自分のセッションでしか見えず、ROLLBACK で無効化できます。

基本構文

-- 標準SQL / MySQL / PostgreSQL
BEGIN;
UPDATE accounts SET balance = balance - 100 WHERE id = 1;
COMMIT;             -- 確定

-- SQL Server
BEGIN TRANSACTION;
UPDATE accounts SET balance = balance - 100 WHERE id = 1;
COMMIT TRANSACTION; -- COMMIT TRAN でも可

-- Oracle
UPDATE accounts SET balance = balance - 100 WHERE id = 1;
COMMIT;             -- BEGIN は不要、DML 開始時に暗黙開始

-- COMMIT WORK は標準SQLの古い書き方(同義)
COMMIT WORK;

明示 COMMIT と暗黙 COMMIT

種類発生条件
明示 COMMITアプリが COMMIT を実行COMMIT;
暗黙 COMMIT (DDL)DDL 実行時に自動CREATE / ALTER / DROP / TRUNCATE
暗黙 COMMIT (制御)セッション終了時正常切断 (autocommit ON 時)
暗黙 COMMIT (管理)SET autocommit=1 等SET 文一部 / LOCK TABLES (MySQL)

DDL の暗黙コミットの落とし穴

BEGIN;
INSERT INTO logs(msg) VALUES ('start');
CREATE TABLE tmp (id INT);       -- ★ MySQL/Oracle ではここで暗黙 COMMIT
INSERT INTO logs(msg) VALUES ('mid');
ROLLBACK;                        -- もう start を消せない

-- PostgreSQL なら DDL もロールバック可能
BEGIN;
CREATE TABLE tmp (id INT);
ROLLBACK;                        -- tmp テーブルも消える

Autocommit と SET AUTOCOMMIT=0

-- MySQL
SELECT @@autocommit;             -- 1 (ON) / 0 (OFF)
SET autocommit = 0;              -- 明示 COMMIT モード

UPDATE accounts SET balance = 0 WHERE id = 1;
-- まだ COMMIT されていない。別セッションからは見えない
COMMIT;                          -- ここで初めて永続化

-- セッション内だけで OFF
SET SESSION autocommit = 0;

-- PostgreSQL の psql 対話モード
\set AUTOCOMMIT off

エラー時の自動ロールバック

多くのDBは、トランザクション中にエラーが発生すると以降のステートメントを拒否します。COMMIT を実行しても ROLLBACK 扱いになります(DB別に挙動差あり)。

-- PostgreSQL: 1つでもエラーが出るとトランザクションは ABORT 状態
BEGIN;
INSERT INTO users(id, name) VALUES (1, 'taro');
INSERT INTO users(id, name) VALUES (1, 'jiro');  -- 主キー重複エラー
SELECT 1;                        -- ERROR: current transaction is aborted
COMMIT;                          -- 実質 ROLLBACK

-- MySQL: エラーが出た文だけ無効。他の文は生きる
-- → 明示的に ROLLBACK 推奨

Two-Phase Commit (XA トランザクション)

複数のDBを1つの論理トランザクションとして扱うための仕組み。第1段階で全DBに「コミットできるか」を確認 (PREPARE)、全員OKなら第2段階で実際の COMMIT を実行します。

-- MySQL XA (例)
XA START 'tx1';
UPDATE accounts SET balance = balance - 100 WHERE id = 1;
XA END 'tx1';

XA PREPARE 'tx1';                -- 第1段階: コミット可能性を保証
-- 別のDBでも同様の PREPARE を実行
XA COMMIT 'tx1';                 -- 第2段階: 確定
-- 失敗時は XA ROLLBACK 'tx1';

-- Java EE / Spring の JTA で透明に利用可能

言語別 commit() メソッド

Java JDBC

Connection conn = DriverManager.getConnection(url, user, pass);
conn.setAutoCommit(false);       // 明示 COMMIT モード
try {
    PreparedStatement ps = conn.prepareStatement("UPDATE accounts SET balance = balance - ? WHERE id = ?");
    ps.setBigDecimal(1, new BigDecimal("100"));
    ps.setLong(2, 1L);
    ps.executeUpdate();
    conn.commit();               // 確定
} catch (SQLException e) {
    conn.rollback();             // 巻き戻し
    throw e;
} finally {
    conn.close();
}

PHP PDO

$pdo = new PDO($dsn, $user, $pass, [
    PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
]);

$pdo->beginTransaction();
try {
    $pdo->prepare('UPDATE accounts SET balance = balance - ? WHERE id = ?')
        ->execute([100, 1]);
    $pdo->commit();              // 確定
} catch (\Throwable $e) {
    $pdo->rollBack();
    throw $e;
}

Python (psycopg2 / sqlite3 / mysql-connector)

import psycopg2
conn = psycopg2.connect(dsn)
conn.autocommit = False          # 既定で False
cur = conn.cursor()
try:
    cur.execute("UPDATE accounts SET balance = balance - %s WHERE id = %s", (100, 1))
    conn.commit()                # 確定
except Exception:
    conn.rollback()
    raise
finally:
    cur.close()
    conn.close()

COMMIT のパフォーマンスチューニング

  • 毎行 COMMIT は遅い: 1000 行 INSERT で 1000 fsync が走る
  • バッチ COMMIT: 1000 行ごとに 1 COMMIT などで桁違いに高速
  • WAL fsync を緩める(PostgreSQL synchronous_commit=off)はクラッシュ時に最後の数秒消える覚悟が必要
  • MySQL innodb_flush_log_at_trx_commit も同様のトレードオフ(1: 安全 / 2: 速い / 0: 最速 危険)

FAQ

Q: COMMIT 後にやっぱり巻き戻したい
A: 不可能です。新しい UPDATE/DELETE で論理的に元に戻すか、バックアップから戻すしかありません。

Q: COMMIT 中にDBクラッシュしたら?
A: WAL/REDO ログから再起動時にロールフォワード or ロールバックされます。これがACIDのD(永続性)を保証する仕組みです。

Q: AUTOCOMMIT は ON / OFF どちらが良い?
A: 対話的SQLは ON のままで便利。アプリは明示 OFF + コードで COMMIT 制御が推奨。