◀ 3.

Oracle 19cのトランザクション制御|COMMIT・ROLLBACK・分離レベルと接続設定

▶

Oracle Database 19cを中心に、確定・取消・同時実行と接続設定を分ける入口です。OracleのPL/SQL BEGINと他製品のtransaction開始文、文の失敗と全体取消を同一視しません。

Oracle19cのtransactionの開始・途中・終了の条件を分ける模式図。実機検証ではない
同じ接続の未確定範囲を確認する模式図です。全エラー/全clientでの取消・永続化・復旧成功を保証する図ではありません。

各コマンドは子ページから選んでください

確定・取消・部分取消の詳細は、次の子ページから選んでください。それぞれの対象範囲と実行条件を確認できます。

  1. COMMIT (トランザクション制御):実結果の確認と確定
  2. ROLLBACK:未確定の変更の取消
  3. SAVEPOINT:同じtransaction内の部分取消

SQL分類全体は親のSQLへ戻れます。以下の製品/言語別の例は比較教材で、一続きの実行手順ではありません。Oracle新旧SQL・client/driver/frameworkの全例は実機未検証です。

この記事の要点
  • トランザクションは論理的な処理単位。失敗した文だけの取消と全体取消を分け、確定前に業務全体の結果を確認する
  • 基本は製品別の開始とCOMMIT / ROLLBACK / SAVEPOINT。OracleのPL/SQL BEGINをSQL transaction開始文にしない
  • ACID 特性: 原子性 / 一貫性 / 独立性 / 永続性
  • 分離レベルは製品ごとの対応・既定値・読み方を確認。名称順から性能順位や全製品の同じ分離保証を決めない
  • Springの@TransactionalとLaravelのDB::transaction()は別のAPI。設定/同一DB接続/例外・再試行の境界を確認する

トランザクションとは

トランザクションは1つ以上のSQL文をまとめる論理的な処理単位です。原子性は、1文が失敗すればアプリの全処理や外部副作用まで自動取消されるという意味ではありません。未確定の残りの処理・実件数・業務条件を確認して終了を選びます。代表例は銀行振込: 口座A から減算する UPDATE と、口座B に加算する UPDATE は片方だけ成功してはいけません。

基本構文(BEGIN / COMMIT / ROLLBACK)

製品別の独立した旧例です。OracleのDML開始とPL/SQL BEGINは別で、PG/MySQL/SQL Serverの開始構文を混ぜません。送金例は更新件数・業務条件・同一接続/自動確定の前提を省略し、成功を保証しません。各更新結果を確認して確定/未確定部分の取消を選び、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(原子性)同じtransactionの確定/取消単位。失敗文だけの取消と全体取消は別Undo ログ / Rollback Segment
Consistency(一貫性)宣言した制約等の整合性。未定義の業務ルールまでDBが自動保証する意味ではない制約検査 / トリガ
Isolation(独立性)指定した分離レベルの規則。全分離レベルが直列実行と同じ結果になるわけではないロック / MVCC
Durability(永続性)永続化と成功応答の関係は製品・同期設定/障害条件を確認。全設定の無損失保証ではないREDO ログ / WAL

SAVEPOINT で部分ロールバック

旧SAVEPOINT例はPG/MySQL等の比較です。Oracleへ冒頭BEGINとRELEASE SAVEPOINTをそのまま転用しません。OracleはROLLBACK TO SAVEPOINTと全ROLLBACK/COMMITを区別し、確定/DDLをまたいで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)

分離レベルは未確定変更だけでなく、再読取り・範囲の行集合・直列化異常等の条件も定めます。次表は比較用の一般的な最小保証であり、Oracleの対応はREAD COMMITTED/SERIALIZABLEとREAD ONLY等の条件で確認します。PGのREAD UNCOMMITTEDはREAD COMMITTEDとして扱われ、REPEATABLE READも標準より強い保証があります。

レベルDirty ReadNon-RepeatablePhantom性能
READ UNCOMMITTED発生発生発生固定の性能順位ではない
READ COMMITTED (PG/Oracle 既定)防ぐ発生発生負荷・競合・処理で比較
REPEATABLE READ (MySQL 既定)防ぐ防ぐ発生※製品・読み方で比較
SERIALIZABLE防ぐ防ぐ防ぐ失敗時の再試行等も含め比較

※ MySQL InnoDBの通常のconsistent readはsnapshotを使い、locking read/DMLのnext-key/gap lockとは区別します。REPEATABLE READならすべて同じ読み方でphantomを防ぐとは一般化しません。PG REPEATABLE READはphantomを防ぎますが直列化異常は別、OracleへREPEATABLE READを設定する例としては読みません。

旧設定比較は製品別です。冒頭のSET TRANSACTION→BEGINという順序をPGへ転用しません。PG18でBEGIN/START TRANSACTION前のSET TRANSACTIONはwarningだけで効果がありません。PGはBEGIN後かつ最初のquery/DML前にSET TRANSACTIONを指定するか、BEGIN ISOLATION LEVEL READ COMMITTED等で開始条件を指定します。Oracle19cではREAD COMMITTED/SERIALIZABLE等の対応とSET TRANSACTIONがtransaction最初の文という条件を確認し、PL/SQL BEGINを開始命令として追加しません。clientが自動開始していれば状態も確認します。SET SESSIONや@@/SHOWはOracle共通ではなく、既存session設定を検証のために変更する手順ではありません。

-- 分離レベルの設定
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)競合する変更等を制限するが、MVCCの通常consistent readまで一律に禁止する意味ではないSELECT ... FOR UPDATE / UPDATE/DELETE
Intention Lock行ロック取得意図のテーブルロックInnoDB が自動付与
Gap Lockインデックス範囲の隙間ロック (MySQL)InnoDBのlocking read/DML・索引/検索条件等に依存。通常snapshot SELECTへ一律付与とはしない

デッドロック

複数処理のロック待ちが循環して進めない状態です。検知・取消の単位は製品/エラー次第で、InnoDB deadlockの全transaction取消とOracleの失敗文の取消を分けます。業務単位を確認して終了/再試行し、結果不明の処理を無条件再送しません。

旧デッドロック例のBEGIN/ERROR1213はMySQL等の比較でOracle共通ではありません。ロック順統一は有用ですが、競合やdeadlockを完全になくす保証ではありません。InnoDB全体取消とOracleの失敗文取消を分け、業務単位を終了/確認した上で再試行を判断します。

-- トランザクション 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

Oracle19cのDML開始とclient/driverの自動確定設定は別です。SQL*Plusは通常のDMLを既定自動確定しませんが、JDBC等のclient条件も確認します。MySQLのsession autocommitやpsqlの既定ONと全clientを同一視せず、transaction開始前に同じ接続の設定を確認します。

旧autocommit例はMySQL/psql向けです。SET autocommit=0は既存接続の設定を変え持ち越され得ます。psqlの既定ONと設定を変えた接続を区別し、OracleのDML開始・SQL*Plus/JDBC等のclient設定へ転用しません。

-- MySQL: 確認と切替
SELECT @@autocommit;            -- 1=ON
SET autocommit = 0;             -- OFF。明示的に COMMIT/ROLLBACK 必要

-- PostgreSQL の psql は対話モードでも文ごとに自動 COMMIT
-- BEGIN ... COMMIT で囲めばトランザクション

アプリ側での書き方

Spring (Java) - @Transactional

旧Spring例は有効なtransaction manager・proxy等の設定と境界経由の呼出しを前提とする断片です。既定proxyで同じobject内のself-invocationへ注釈だけで効くとはしません。この例はrollbackFor=Exception.classを指定しますが、例外を内部で握り潰す場合や、0件更新/業務失敗/外部送信まで自動検知・取消する完成実装ではありません。

@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

旧Laravel例は同じtransactionalなDB接続の変更を対象とします。例外がclosure外へ出ることと、0件更新/業務ルール違反の検知は別です。第2引数3は最初を含む最大試行数で3回追加retryではなく、再実行され得るclosure内へ外部送信等を無造作に含めません。DDL暗黙COMMIT・別接続・既存確定まで取消されるとは保証しません。

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: Oracle19cの通常表DDLは構文上有効な文の実行前と成功後に暗黙COMMIT。MySQLにも対象文/一時表等の例外があり、PGの通常CREATE TABLEは明示transaction内で取消可能です。全DDLを同一視せず、途中へDDLを混ぜて先行DMLまで戻せると期待しません。

Q: 分離レベルはどれを選ぶべき?
A: 必要な読み取り/更新の整合性、製品の実装、競合と再試行の方針で選びます。全業務でREAD COMMITTEDが十分とはせず、OracleにREPEATABLE READを選べるとも扱いません。高い分離名だけで業務ルール/残高/一意性を自動保証しません。

Q: COMMIT し忘れたまま接続切断したらどうなる?
A: clientの終了方法と設定を確認します。SQL*Plusの既定EXITCOMMIT ONでは引数なしEXITで未確定分をCOMMITします。AUTOCOMMIT OFFかつEXITCOMMIT OFFでは引数なしEXITで未確定分をROLLBACKし、異常終了時の取消とも区別します。設定の変更やEXIT ROLLBACKで既に確定した変更を戻すことはできません。終了前に同じ接続で明示的にCOMMIT/ROLLBACKを選びます。通常の一貫性読取りで他者の未確定変更は見えませんが、dirty readを許す他製品の設定へ一般化しません。通信切断だけで確定成否を断定しません。

一次資料と確認範囲

Oracle19cのTransactions・Concurrency/Consistency・COMMIT・SQL*Plus EXIT、PG18分離レベル、InnoDB consistent read、Spring transaction注釈、Laravel13 DB transactionを照合しました。これらの製品/driver/frameworkの旧コード実行・全設定/障害・性能/復旧は未検証です。

client終了時の設定の組合せはSQL*Plus19c SET EXITCOMMIT、PGの設定順はPostgreSQL18 SET TRANSACTIONも確認してください。OracleとPGへ同じBEGIN/SETの順を転用しません。

子ページ
  1. COMMIT (トランザクション制御)
  2. ROLLBACK
  3. SAVEPOINT
同階層のページ
  1. DDL
  2. DML
  3. トランザクション制御 (SQL)
  4. データディクショナリ
  5. 動的パフォーマンスビュー (V$ビュー)
  6. 関数

最近更新/作成されたページ