ROLLBACK文を使用すると、保留状態のデータベースへの変更を取り消せます。たとえば表から行を誤って削除したときなどは、ROLLBACK文を使用して元のデータをリストアできます。TO SAVEPOINT句を使用すると、現行のトランザクションの途中の文までロールバックできます。したがって、変更をすべて取り消す必要はありません。
未完成のトランザクションを開始した場合(たとえば、SQL文が正常に実行されないなど)、ROLLBACKを使用すると起点まで戻ることができるため、データベースの整合性が維持されます。特に、ROLLBACK文では次の処理が実行されます。
カレント・トランザクションで実行されたデータベースの変更を取り消します。
すべてのセーブポイントを消去します。
トランザクションを終了します
解析ロック以外の行および表のロックをすべて解除します。
CURRENT OF句で参照されているカーソルをクローズします。MODE=ANSIの場合は、すべての明示カーソルをクローズします。
ROLLBACK文は、ホスト変数の値やプログラム内の制御の流れには影響を与えません。
MODE=ORACLEの場合、CURRENT OF句で参照されていない明示カーソルは、ROLLBACKの前後もオープンしたままです。
特に、ROLLBACK TO SAVEPOINT文では次の処理が実行されます。
指定したセーブポイントがマークされた以降のデータベースへの変更を取り消します。
指定したセーブポイント以降のセーブポイントをすべて消去します。
指定したセーブポイントがマークされた以降に取得された行および表のロックをすべて解除します。
ROLLBACK文は例外処理の一部になっているため、プログラムのメイン・パスではなくエラー処理ルーチン内に指定する必要があります。次の例では、トランザクションをロールバックして、Oracleとの接続を切断します。
EXEC SQL ROLLBACK WORK RELEASE;
オプションのキーワードWORKには、ANSI互換性があります。RELEASEオプションを指定すると、プログラムで使用されているリソースがすべて解放され、データベースから切断されます。
WHENEVER SQLERROR GOTO文からROLLBACK文が記述されているエラー処理ルーチンに分岐したときに、ROLLBACKでエラーが発生すると、プログラムが無限にループする可能性があります。無限ループを回避するには、次に示すようにROLLBACK文の前にWHENEVER SQLERROR CONTINUEを記述します。
EXEC SQL WHENEVER SQLERROR GOTO sql_error;
for (;;)
{
printf("Employee number? ");
gets(temp);
emp_number = atoi(temp);
printf("Employee name? ");
gets(emp_name);
EXEC SQL INSERT INTO emp (empno, ename)
VALUES (:emp_number, :emp_name);
...
}
...
sql_error:
EXEC SQL WHENEVER SQLERROR CONTINUE;
EXEC SQL ROLLBACK WORK RELEASE;
printf("Processing error\n");
exit(1);
プログラムが異常終了すると、Oracleによりトランザクションが自動的にロールバックされます。
関連項目:
Oracleは、SQL文を実行する前に、暗黙的なセーブポイント(ユーザーは操作できません)を設定します。したがって、この文が失敗すると、自動的にロールバックされ、SQLCA内のsqlcodeに適切なエラー・コードが戻されます。たとえば、INSERT文が一意の索引内に同じ値を挿入しようとしたためエラーが発生すると、この文はロールバックの対象になります。
Oracleは、デッドロックを解除するために単一のSQL文をロールバックすることもあります。Oracleは関係しているトランザクションの1つにエラーを通知し、そのトランザクション中の現在の文をロールバックします。
失われるのは失敗したSQL文で開始された作業のみです。つまり、現行のトランザクション内でこの文より前に行われた作業は保存されます。したがって、データ定義文が失敗しても、それ以前の自動コミットは取り消されません。
SQL文は実行前に必ず解析され、構文規則に従っているか、有効なデータベース・オブジェクトを参照しているかが検証されます。SQL文の実行中にエラーが検出されると、ロールバックが発生しますが、解析中にエラーが検出されても、ロールバックは発生しません。