初めに
現代のウエブ開発には、無数の言語、ライブラリー、テクノロジがあります。UIデザインやユーザー・エクスペリエンス等、技術以外の知識も把握しなければならなりません。開発者は、エキスパートになるまで数年がかかってしまいます。
Oracle APEXとはロー・コード開発プラットフォームです。APEXで、簡単で、高速にアプリケーションをゼロから作成し、技術の詳細を気にせずビジネス課題に集中することだできます。一方、プラットフォームなので、普段開発者が管理できることはプラットフォームが管理を引き受けますので、行動が自動か、手動に行うことを把握しなければなりません。
データの保全することにトランザクション処理が重要なことなので、APEXのトランザクション処理を洗い出しましょう。
トランザクションとは?
データベースのトランザクションとは、複数のSQL文を1つの処理としてまとめてデータベースに反映させることです。
例えば、銀行のシステムに、あるアカウントから他のアカウントに振り込む行動を想像してください。一つだけじゃなくて、2つの変更が必要です:
- アカウントAの残高を減らす
- アカウントBの残高を増やす
以上の操作の中に、すべての操作を行わなければならなりません。だからSQL文を1つの処理としてまとめることになり、トランザクションと呼ばれます。
CommitとRollback
APEXのトランザクション処理を理解するには、まずcommit
とrollback
というSQLコマンドを理解しなければなりません。
このコマンドでトランザクションを終了することができます。
commit
は、データの変更がまとめてデータベースに格納されます。
rollback
は、トランザクション内でのデータの変更がすべてキャンセルされます。
APEXのトランザクション
APEXのページには、「プロセス」と「動的アクション」でPL/SQL文を書くことができます。
「プロセス」と「動的アクション」もPL/SQL文を実行すると、トランザクションが開始されます。もちろん以上のcommit
とrollback
コマンドで、手動的にトランザクションを終了することができますが、自動的にcommit
とrollback
が実行されます。こういう場合はデータが案外な状態になってしまう恐れがありますので、注意が必要です。
APEXは、いつ自動的にコミットする?
APEXのトランザクション処理の情報はドキュメンテーションにはありませんので、調査で以下のタイミングで自動的にコミットすることを確認しました:
- COMMITを書く時
- 動的アクションのアクションの終了の時
- すべてのプロセスの終了の時(レンダリング前)
- すべてのプロセスの終了の時(ページ送信後)
- 一つのプロセスが終了し、セッション・ステートが更新された時
-
APEX_MAIL.PUSH_QUEUE
の実行時- まだ確認していないですが、この記事によってコミットしてしまうらしいです。
APEXは、いつ自動的にロールバックする?
エラーが処理中に発生したら、自動的にロールバックされる。どこまでロールバックするのは、最後のコミットの時まで。まだコミットしなかった場合はトランザクションの前の状態までロールバックします。
テストケースのセットアップ
自動commit
とrollback
を理解するため、テストケースで確認しましょう。
テストテーブル
テストプロシージャ
create or replace procedure "TCR_SIMPLE_UPDATE"
(in_value IN NUMBER,
in_value2 IN VARCHAR2)
is
begin
update test_commit_rollback set value = in_value;
update test_commit_rollback set value2 = in_value2;
end;
テストページ
APEXのページを作成し、以下のようなフォームリージョンを追加しました。
プロセス
プロセスは原則、全部のプロセスが終わった時にコミットする。複数のプロセスがあっても、自動コミットは一回だけです。
例
- DBの状況:
Value = 1, Value2 = a
- ページ送信後、プロセスを2つ実行する
- タイプ:PL/SQL実行
TCR_SIMPLE_UPDATE(:P2_VALUE,:P2_VALUE2);
- タイプ:PL/SQL実行
ROLLBACK;
- VALUEを2、VALUE2をbに更新する
結果:
- VALUE = 1, VALUE2 = a
- 最初までROLLBACKする。プロセス後コミットされないらしい。
プロセスの実行タイミングが違う場合もコミットは一回です。以下の例で、After Submitのタイミングじゃなくて、Processingのタイミングの後、コミットすることになります。
例
- DBの状況:
Value = 1, Value2 = a
- 「After Submit」のタイミングに、プロセスを作成
TCR_SIMPLE_UPDATE(2,'b');
- 「Processing」のタイミングに、プロセスを作成
TCR_SIMPLE_UPDATE(3,'c'); ROLLBACK;
結果:
- VALUE = 1, VALUE2 = a
※プロセスの実行順序はAfter Submit > Validation > Processing
セッション変更時のコミット
前に、「プロセスは原則、全部のプロセスが終わった時にコミットする」と書きましたが、例外があります。セッション・ステートを変更すると、コミットしてしまう場合があります。
セッション・ステート変更する操作
-
PX_ITEM := ○○
(直接アイテムを兼行する) -
apex_util.set_session_state(PX_ITEM, 値)
- ※
apex_util.set_session_state(PX_ITEM, 値, false)
は安全です (ドキュメンテーション)
- ※
-
SELECT INTO :PX_ITEM
文 -
RETURNING INTO :PX_ITEM
文 - Out変数をページアイテムに挿入する
- APEX Computation(計算)
例:別プロセスでセッション・ステートを変更する
- ページ送信後、プロセスが実行する
- DBの状況:
Value = 1, Value2 = a
- 「コード実行1」タイプ:PL/SQL実行
TCR_SIMPLE_UPDATE(2,'b');
- 「ステート変更1」タイプ:PL/SQL実行
:P2_ITEM := 2;
- 「コード実行2」タイプ:PL/SQL実行
TCR_SIMPLE_UPDATE(3,'c');
- 「ステート変更2」タイプ:PL/SQL実行
:P2_ITEM := 3;
- 「コード実行3」タイプ:PL/SQL実行
ROLLBACK;
- DBの状況:
結果:
- VALUE = 3, VALUE2 = c
- 期待は、
VALUE = 1, VALUE2 = a
が、ステート変更後、コミットしてしまうことがあります。
例:別プロセスでセッション・ステートの値を変更しない
- ページ送信後、プロセスが実行する
- DBの状況:
Value = 1, Value2 = a
- 「コード実行1」タイプ:PL/SQL実行
TCR_SIMPLE_UPDATE(2,'b');
- 「ステート変更1」タイプ:PL/SQL実行
:P2_ITEM := 2;
- 「コード実行2」タイプ:PL/SQL実行
TCR_SIMPLE_UPDATE(3,'c');
- 「ステート変更2」タイプ:PL/SQL実行
:P2_ITEM := 2; --以上と変更はなし
- 「コード実行3」タイプ:PL/SQL実行
ROLLBACK;
- DBの状況:
結果:
- VALUE = 2, VALUE2 = b
- 期待は、
VALUE = 1, VALUE2 = a
が、「ステート変更1」後、コミットしてしまうことがあります - 「ステート変更2」は、ステート変更使用としましたが、値は現在の値と同じなので、コミットは実行しません。
例:プロセス内
- ページ送信後、プロセスが実行する
- DBの状況:
Value = 1, Value2 = a
- 「コード実行」タイプ:PL/SQL実行
- DBの状況:
TCR_SIMPLE_UPDATE(2,'b');
:P2_ITEM := 2;
TCR_SIMPLE_UPDATE(3,'c');
:P2_ITEM := 3;
ROLLBACK;
結果:
- VALUE = 1, VALUE2 = a
- コミットはプロセスが終わった時に実行します。コードをまとめて一つのプロセスで実行すると、コミットする機会はなさそうです。
動的アクション
動的アクションは、プロセスと違って、各アクションの後コミットされます。
例
- DBの状況:
Value = 1, Value2 = a
- ボタンを押すと、動的アクションが実行する
- タイプ:PL/SQL実行
TCR_SIMPLE_UPDATE(2,'b');
- タイプ:PL/SQL実行
ROLLBACK;
結果:
- VALUE = 2, VALUE2 = b
- 最初のアクションが終了したからCOMMITします。
参照(英語版)
- Ted Struik Blog : Rollback & Commit
- https://tedstruik-oracle.nl/ords/f?p=25384:1065::::::
- 更新:2018-05-30
- How to make a deferred commit Q&A
- When is commit executed? Q&A
- Jeff Kemp Blog : Session State May or May Not Commit
- Implicit commits in APEX