Oracle Database 19c の SAVEPOINT は、同じトランザクション内で変更の一部を取り消すための目印です。ROLLBACK TO はそこより後の変更を戻しますが、トランザクションを終了しません。
| この記事の要点 |
|
SAVEPOINT とは
トランザクション制御のうち、全体の ROLLBACK と部分的な ROLLBACK TO を使い分けるための機能です。Oracle は最初の実行可能な SQL によりトランザクションを暗黙に開始します。同名の保存点を作り直すと、その名前は新しい位置を指します。Oracle 19c SAVEPOINT
基本構文
同じ接続の、まだ COMMIT していない処理の中で使用します。次の二つの ROLLBACK TO は代替表記です。
SAVEPOINT sp_name;
ROLLBACK TO SAVEPOINT sp_name;
-- 同じ意味の別表記: ROLLBACK TO sp_name;
保存点が作られた後の DML が取り消され、指定点とそれ以前の保存点は残ります。指定点より後の保存点は消えます。同じ指定点へ繰り返し戻れます。Oracle 19c ROLLBACK
実習前の準備
以下は実行結果を掲載したものではなく、Oracle 19c 用の教材です。使い捨ての専用スキーマで、自分の表を作成・参照・更新でき、以下の名前が未使用であることを前提にします。他の未確定作業がない接続で準備を終え、実習中は同じ接続を使います。DDL を実習の途中へ挟みません。
CREATE TABLE w38_sp_customers (
id NUMBER PRIMARY KEY,
name VARCHAR2(100) NOT NULL
);
CREATE TABLE w38_sp_addresses (
customer_id NUMBER REFERENCES w38_sp_customers(id),
addr VARCHAR2(100)
);
CREATE TABLE w38_sp_points (
customer_id NUMBER REFERENCES w38_sp_customers(id),
point NUMBER
);
CREATE TABLE w38_sp_orders (
id NUMBER PRIMARY KEY,
label VARCHAR2(10)
);
クライアントの自動コミットを無効にします。SQL*Plus なら次は SQL ではなくクライアントコマンドです。他のツールや JDBC では、その接続の設定方法を確認してください。
SET AUTOCOMMIT OFF
典型的な使用例
顧客登録は維持し、任意の住所登録だけを取り消して、ポイント登録へ進む例です。表は準備直後の空の状態を前提にします。エラーを実際に起こす例ではなく、取消分岐を明示的に通します。
INSERT INTO w38_sp_customers (id, name) VALUES (1, 'Alice');
SAVEPOINT after_customer;
INSERT INTO w38_sp_addresses (customer_id, addr) VALUES (1, 'Tokyo');
ROLLBACK TO after_customer;
INSERT INTO w38_sp_points (customer_id, point) VALUES (1, 100);
SELECT id, name FROM w38_sp_customers ORDER BY id;
SELECT customer_id, addr FROM w38_sp_addresses ORDER BY customer_id;
SELECT customer_id, point FROM w38_sp_points ORDER BY customer_id;
ROLLBACK;
SELECT 時点の期待状態は顧客1件、住所0件、ポイント1件です。最後は実習用に全体を ROLLBACK するため、顧客とポイントも取り消されます。業務で保存する場合の COMMIT はこれとは別の選択です。
ROLLBACK との違い
| 命令 | 変更への作用 | 継続と保存点 |
|---|---|---|
| ROLLBACK | 現在のトランザクションの未確定変更全体を取消 | 終了し、全保存点を消す |
| ROLLBACK TO SAVEPOINT sp | sp より後だけ取消 | 継続。sp と以前の点を保持、後の点を消す |
| COMMIT | 現在のトランザクション全体を確定 | 終了し、全保存点を消す |
| RELEASE SAVEPOINT sp | 対応製品で保存点を解放。変更取消とは別 | Oracle 19c では使用不可。比較先ごとの境界に注意 |
Oracle の通常の DDL は、構文として有効な文の実行前に暗黙 COMMIT を行い、成功後にも COMMIT します。実行エラーになった DDL でも、直前の DML が未確定のまま残るとは限りません。自動コミットが無効でもこの境界は別に存在します。Oracle 19c COMMIT
ネストして使う
準備した空の w38_sp_orders を使います。保存点の重なりを観察する例で、独立した内部 COMMIT の例ではありません。
INSERT INTO w38_sp_orders (id, label) VALUES (1, 'A');
SAVEPOINT sp1;
INSERT INTO w38_sp_orders (id, label) VALUES (2, 'B');
SAVEPOINT sp2;
INSERT INTO w38_sp_orders (id, label) VALUES (3, 'C');
SAVEPOINT sp3;
INSERT INTO w38_sp_orders (id, label) VALUES (4, 'D');
ROLLBACK TO sp3;
SELECT id, label FROM w38_sp_orders ORDER BY id;
ROLLBACK TO sp2;
SELECT id, label FROM w38_sp_orders ORDER BY id;
ROLLBACK;
最初の SELECT は1・2・3、次は1・2が残る期待です。sp2 へ戻った後に sp3 は参照できません。sp2 は残ります。最後の全体 ROLLBACK は1・2も戻します。
DBMS 別の対応状況
| 製品・参照範囲 | 保存点の操作 | 区別したい点 |
|---|---|---|
| PostgreSQL 18 | SAVEPOINT / ROLLBACK TO / RELEASE SAVEPOINT | SQL のトランザクションブロック内。同名の古い点は新しい同名点を解放すると再び参照可能 |
| MySQL 8.4 / MariaDB公式資料 | InnoDB で SAVEPOINT / ROLLBACK TO / RELEASE SAVEPOINT | 非トランザクション表の変更を取消できるという意味ではない。全エンジンを同一扱いにしない |
| Oracle 19c | SAVEPOINT / ROLLBACK TO [SAVEPOINT] | RELEASE SAVEPOINT なし |
| SQL Server | SAVE TRANSACTION / ROLLBACK TRANSACTION | Oracle の構文と異なる |
| SQLite公式資料 | SAVEPOINT / ROLLBACK TO / RELEASE | 外側の BEGIN がなくても開始可能。最外の RELEASE はトランザクション確定となり得る |
| Db2 | 旧例は SAVEPOINT sp ON ROLLBACK RETAIN CURSORS | この構文の対象製品・版は未確認。実行前に該当版の資料で確認する |
MySQL、MariaDB、PostgreSQL、SQLiteを比較しています。単なる「SQL標準対応」というラベルから、保存点の寿命まで同じと判断しないでください。
SQL Server の独自構文
既存例は末尾の「既存コードの製品別補足」S4に残しています。orders(id, label) のような2列の空の教材表、主キー重複のない値、未開始の専用接続を前提にします。BEGIN TRANSACTION / SAVE TRANSACTION / ROLLBACK TRANSACTION は T-SQL の比較で、Oracle に貼り付ける手順ではありません。Microsoft SAVE TRANSACTION
エラーハンドリングとリトライ
保存点はDB内の取消位置を作りますが、接続切断やトランザクション全体が失われた場合にも継続できる保証はありません。エラー分類と現在のトランザクション状態を確認し、再試行するなら同じ処理の二重実行も考慮します。
既存の決済例S5は、SQLのBEGIN、PL/pgSQLのPERFORM、例外ブロック内のROLLBACK TOを混ぜた断片です。Oracleの実行例ではなく、PostgreSQL 18でもPL/pgSQL内の保存点コマンドはサポートされません。外部決済はDBのROLLBACK TOで取り消せません。決済側の状態照会・冪等性・取消手段を別途設計する必要があります。PostgreSQL PL/pgSQL transaction management
フレームワークでの利用
Spring (Java) のネストトランザクション
S6の二つのサービスは、別Beanのトランザクションプロキシを経由する概念例です。import、依存注入、Order/StockException等の定義を省略しており、そのままコンパイルする完成例ではありません。Spring 6.2のNESTEDは単一物理トランザクションの保存点を利用し、通常JDBCリソース向けです。使用するtransaction managerとドライバの対応が前提です。REQUIRES_NEWは独立した物理トランザクションで、外側のROLLBACKと運命を共有する保存点ではありません。Spring公式説明
Laravel (PHP) のネストトランザクション
S7は[...]の列・値を省略した構造例です。Laravel 13の実装はgrammarのsupportsSavepoints判定を使います。内側の終了が外側と独立して物理COMMITされるわけではありません。同一connection、対応driver/grammar、例外発生時の状態が前提で、Oracleドライバとの動作確認をした例ではありません。すべてのThrowableを握りつぶして処理継続できるという意味でもありません。Laravel公式ソース
よくあるトラブル
| 症状 | 確認する境界 | 対処の考え方 |
|---|---|---|
| SAVEPOINT can only be used in transaction blocks | PostgreSQLのSQLトランザクション外の例 | PostgreSQLのBEGINが必要な場面。OracleにBEGINを追加する指示ではない |
| savepoint "sp" does not exist | 名前、接続、全体終了、後方点へのROLLBACK TO | 点が消えた原因を確認。名前だけ直して復旧を保証しない |
| 自動コミットで保存点が使えない | 使用クライアント・接続のcommit設定 | 接続設定を確認。SET autocommit=0をOracle SQLとして使わない |
| MySQLでMyISAMを使用 | 表のストレージエンジン | 非トランザクションの変更は取消対象にできない。既存表の変換を自動対処にしない |
FAQ
多数の保存点は性能に影響する? 保存点数だけで許容性能を決めることはできません。「数十なら問題ない」という一律の閾値は設けず、対象DB・処理・負荷で判断します。ここに実測値はありません。
同じ名前を再使用すると? Oracle 19cでは以前の同名点は消え、新しい位置になります。PostgreSQLの同名点の扱いとは異なります。
COMMIT後に戻れる? 保存点は消えます。保存点はバックアップではなく、トランザクションをまたぐ復元手段ではありません。
既存コードの製品別補足
以下は元記事の7個のコード資産を、用途と制限を付けて保持したものです。Oracle 19cの実習には本文のw38_sp_*例を使い、別製品・不完全な断片を一続きに実行しないでください。
S1
S1: 既存の構文比較。RELEASE SAVEPOINTはMySQL/PostgreSQL等の比較でありOracle19cでは使えません。実行可能な一連の処理ではなく、保存点名を使う構文断片です。ROLLBACK TOの2行は代替表記です。
-- 設置
SAVEPOINT sp_name;
-- 巻き戻し(SAVEPOINT 自体は残り、再利用可能)
ROLLBACK TO SAVEPOINT sp_name;
ROLLBACK TO sp_name; -- SAVEPOINT 省略可(多くの DB)
-- 解放(明示的に SAVEPOINT を消す)
RELEASE SAVEPOINT sp_name;
S2
S2: SQLのBEGINを持つ旧比較例。Oracle実習は本文のw38_sp_*版を使います。比較先ではcustomers(id,name)、addresses(customer_id,addr)、points(customer_id,point)と必要な制約・未使用id=1、自動コミット無効の専用接続が必要です。INSERT成功後に明示的取消を通す例で、任意のSQLエラーから復帰する完成処理ではありません。COMMITは実際の確定です。
BEGIN;
-- 1段階目: 顧客登録
INSERT INTO customers (id, name) VALUES (1, 'Alice');
SAVEPOINT after_customer;
-- 2段階目: 任意の住所登録(エラー許容)
INSERT INTO addresses (customer_id, addr) VALUES (1, 'Tokyo');
-- もし制約違反やビジネスロジックで失敗したら
ROLLBACK TO after_customer;
-- → addresses への INSERT は消える、customers は残る
-- 3段階目: ポイント付与(必須)
INSERT INTO points (customer_id, point) VALUES (1, 100);
COMMIT;
-- → customers と points は確定、addresses は無し
S3
S3: SQLのBEGINを持つ旧比較例。ordersがidと文字列の2列でid=1から4が未使用、明示トランザクションと保存点を扱う製品の専用接続が前提です。Oracle実習は本文を使用します。保存点の重なりであり独立COMMITではなく、SQL標準全製品の細部の証明でもありません。
BEGIN;
INSERT INTO orders VALUES (1, 'A');
SAVEPOINT sp1;
INSERT INTO orders VALUES (2, 'B');
SAVEPOINT sp2;
INSERT INTO orders VALUES (3, 'C');
SAVEPOINT sp3;
INSERT INTO orders VALUES (4, 'D');
ROLLBACK TO sp3;
-- 4 のみ消える。1,2,3 は残る
ROLLBACK TO sp2;
-- 3 も消える。1,2 が残る(sp3 も自動消滅)
COMMIT;
-- 1, 2 が確定
S4
S4: SQL Serverの比較。空のorders(id,label)教材表、idの一意性、権限、他の開始済みトランザクションのない専用接続が前提です。Oracle用ではありません。末尾COMMITは保存します。
-- SQL Server は SAVE TRANSACTION
BEGIN TRANSACTION;
INSERT INTO orders VALUES (1, 'A');
SAVE TRANSACTION sp1;
INSERT INTO orders VALUES (2, 'B');
ROLLBACK TRANSACTION sp1; -- sp1 以降ロールバック
COMMIT TRANSACTION;
S5
S5: 実行不可の旧決済ハイブリッド断片です。OracleはPERFORMを持たず、PG18 PL/pgSQL内でもSAVEPOINT/ROLLBACK TOはサポートされません。orders列定義やcall_payment_apiも未定義です。SQL/手続き言語の境界と例外後の状態が欠けており、完成例として使いません。DB保存点は外部決済の取消や安全な再送を保証しません。
BEGIN;
INSERT INTO orders (id, total) VALUES (100, 5000);
SAVEPOINT before_payment;
BEGIN
-- 外部決済 API 呼び出し(失敗するかもしれない)
PERFORM call_payment_api(100);
EXCEPTION WHEN OTHERS THEN
ROLLBACK TO before_payment;
-- 失敗時は order を「未払い」状態で残す
UPDATE orders SET status = 'PAYMENT_FAILED' WHERE id = 100;
END;
COMMIT;
S6
S6: Springの省略例です。別サービスBeanのプロキシ経由、対応するJDBC transaction manager/driverと保存点、依存注入、Order/StockException/log/import等の定義が必要です。{ ... }を持ち未完成です。文字列の"等は旧表示の残存エスケープでJava文字列として実行しません。NESTEDは単一物理トランザクションの保存点、REQUIRES_NEWは独立した物理トランザクションです。
@Service
public class OrderService {
@Transactional
public void placeOrder(Order o) {
customerService.register(o.getCustomer());
try {
inventoryService.reserve(o); // NESTED
} catch (StockException e) {
// 在庫不足 → reserve だけ巻き戻し、registerは生きる
log.warn("Stock failure, continue without reservation");
}
}
}
@Service
public class InventoryService {
// 親トランザクションに SAVEPOINT を作る
@Transactional(propagation = Propagation.NESTED)
public void reserve(Order o) { ... }
}
S7
S7: Laravelの省略例です。[...]は実行可能な入力データではありません。同一connection、対応driver/grammar、customers/addresses/pointsと列・値・制約が必要です。すべてのThrowable後に継続できる保証はなく、Oracleドライバの動作検証例でもありません。
DB::transaction(function () {
DB::table('customers')->insert([...]);
try {
// ネスト = 内部で SAVEPOINT 発行
DB::transaction(function () {
DB::table('addresses')->insert([...]);
});
} catch (Throwable $e) {
// addresses INSERT のみロールバック
Log::warning('addr failed but continue');
}
DB::table('points')->insert([...]);
});
子ページはありません
- COMMIT (トランザクション制御)
- ROLLBACK
- SAVEPOINT
人気ページ
- 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・Metasequoiaと用途別の選び方
- 7 Spring Frameworkのアノテーション一覧
- 8 【Spring】@Valueアノテーションとは
- 9 CATALINA_HOME の確認方法 (Linux / Mac)
- 10 【Spring】@Autowiredアノテーションとは
最近更新/作成されたページ
- Visual Studio「デザイナーを表示できません」エラーの原因と対処 2026-10-28 12:06:00
- SSH 認証に失敗しました。再試行してください の対処 2026-10-28 12:06:00
- SSH2 秘密鍵の読み込みに失敗しました の原因と対処 2026-10-28 12:06:00
- TeraTerm のよくあるエラーと対処法完全ガイド — Connection refused / 2026-10-28 12:06:00
- Visual Studio エラー一覧|コンパイルエラー・警告の確認方法と対処 2026-10-28 11:39:57
- Whitelabel Error Page の原因と消し方|Spring Boot のエラーページ 2026-10-28 11:39:57
- Eclipseで「サーバーに追加または除去できるリソースがありません。」の原因と対処法 2026-10-28 11:39:57
- SQL WHERE 句完全ガイド 2026-10-28 11:39:57
- SQL JOIN 完全ガイド (INNER/LEFT/RIGHT/FULL OUTER) 2026-10-28 11:39:57
- tomcat の起動 / 停止ログと catalina.log・catalina.out の違い 2026-10-28 10:24:23
- Tomcat の起動確認方法 5 つ|localhost:8080・ポート・プロセス・ログ 2026-10-28 10:24:23
- Oracle 19c COMMITの使い方: 暗黙コミット・自動確定・応答不明時の確認 2026-10-28 09:59:09
- Oracle 19c DELETE文|削除対象の確認・COMMIT前の判断・ROLLBACKの条件 2026-10-28 09:59:09
- Oracle 19c INSERT文|INSERT ALL・SELECT・RETURNINGとMERGEの使い分け 2026-10-28 09:59:09
- Oracle 19cのトランザクション制御|COMMIT・ROLLBACK・分離レベルと接続設定 2026-10-28 09:59:09