アプリケーションでは、トランザクションを終了させたり、モードを変更させたりすることができます。ここでは、トランザクションの終了方法と、トランザクションモードの変更方法について説明します。
トランザクションの終了方法には、以下の3つの方法があります。
COMMIT文は、トランザクションの区切りを指定するSQL文です。COMMIT文により行われる処理は、以下のとおりです。
処理中のトランザクションを終了し、このトランザクションで行われたデータ操作をデータベースに反映します。
オープン中のすべてのカーソルをクローズします。ただし、トランザクションを超越するカーソルはクローズしません。
このトランザクションで獲得した、データベース資源のロックをすべて解放します。
前に実行したCOMMIT文またはROLLBACK文以後、当該COMMIT文までに行ったデータベースの処理をデータベースに反映します。次に、現在のトランザクションを終了します。一度もCOMMIT文またはROLLBACK文を実行していない場合は、アプリケーションの実行開始から当該COMMIT文までのデータベースの処理をデータベースに反映します。
COMMIT文の形式を以下に示します。
COMMIT WORK
COMMIT文によるデータベース更新の例を以下に示します。
図2.3 COMMIT文によるデータベース更新の例
ROLLBACK文は、トランザクション内で行ったデータベースの処理を取り消すためのSQL文です。ROLLBACK文により行われる処理を以下に示します。
処理中のトランザクションを終了し、このトランザクションで行われたすべての変更を取り消します。データベースは更新されません。
オープン中のすべてのカーソルをクローズします。
このトランザクションで獲得した、データベース資源のロックをすべて解放します。
前に実行したCOMMIT文またはROLLBACK文実行以後、当該ROLLBACK文までに行ったデータベースの処理を取り消します。そして、現在のトランザクションを終了します。一度もCOMMIT文またはROLLBACK文を実行していない場合は、アプリケーションの実行開始から当該ROLLBACK文までのデータベースの処理を取り消します。
ROLLBACK文の形式を以下に示します。
ROLLBACK WORK
ROLLBACK文によるトランザクション取消しの例を以下に示します。
図2.4 ROLLBACK文によるトランザクション取消しの例
アプリケーションがトランザクション開始状態のままCOMMIT文もROLLBACK文も実行せずに終了する場合には、Symfoware/RDBがトランザクションをロールバックします。
トランザクションが開始状態のままアプリケーションが終了する例を以下に示します。
図2.5 トランザクション開始状態でのアプリケーションの終了の例
トランザクションモードの初期値は、動作環境ファイルのDEFAULT_ACCESS_MODEおよびDEFAULT_ISOLATIONで設定します。また、トランザクションモードの変更は、SET TRANSACTION文で行います。トランザクションモードには、以下の2つの項目があります。
トランザクションアクセスモード
独立性水準
トランザクションアクセスモードでは、実行できるSQL文の種類を設定します。トランザクションアクセスモードには、以下の2種類があります。
トランザクションアクセスモードの初期値は、動作環境ファイルのDEFAULT_ACCESS_MODEの指定により決まります。
複数のトランザクションが同じ資源にアクセスする場合、なにも制御を行わないと、データの矛盾が発生してしまいます。独立性水準では、このようなことが起こらないように、あるトランザクションがアクセスしているデータに対し、他のトランザクションによる参照または更新を制御します。また、他のトランザクションが更新中の資源に対し、自トランザクションが参照または更新できるかを制御します。
独立性水準には以下の4種類があります。
独立性水準の初期値は、動作環境ファイルのDEFAULT_ISOLATIONの指定により決まります。ただし、動作環境ファイルのR_LOCKがNOの場合、DEFAULT_ISOLATIONにREPEATABLE_READを指定しても、SERIALIZABLEになります。また、動作環境ファイルのR_LOCKがYESの場合は、DEFAULT_ISOLATIONにSERIALIZABLEを指定しても、REPEATABLE READになります。
独立性水準は、SET TRANSACTION文で変更可能です。
ただし、動作環境ファイルのR_LOCKがNOの場合は、SET TRANSACTION文にREPEATABLE READを指定しても、SERIALIZABLEになります。また、動作環境ファイルのR_LOCKがYESの場合は、SET TRANSACTION文にSERIALIZABLEを指定しても、REPEATABLE READになります。
また、動作環境ファイルでDSO_LOCKを指定した場合、SET TRANSACTION文は指定できません。
参照
SET TRANSACTION文の詳細は、“SQLリファレンス”を参照してください。
あるトランザクションの実行中に現れる可能性のある現象を以下に示します。
現象1)
トランザクションT1が行を更新する。T1がトランザクションを終了する前に、トランザクションT2がその行を読み込む。T1がROLLBACK文を実行した場合、T2は存在しなかった行を読むことになる。
現象2)
トランザクションT1が行を読み込む。トランザクションT2が、その行を更新または削除し、COMMIT文を実行する。T1がその行を再び読もうとした場合、更新した値を受け取るかまたはその行が削除されたことを知る。
現象3)
トランザクションT1が、ある探索条件を満たす行の集合を読み込む。トランザクションT2が、その探索条件を満たす行を追加する。T1が、同じ探索条件で再度行の集合を読み込んだ場合、最初とは異なった行の集合を得ることになる。
独立性水準 | 現象1) | 現象2) | 現象3) |
---|---|---|---|
SERIALIZABLE | 不可能 | 不可能 | 不可能 |
REPEATABLE READ | 不可能 | 不可能 | 可能 |
READ COMMITTED | 不可能 | 可能 | 可能 |
READ UNCOMMITTED | 可能 | 可能 | 可能 |
あるトランザクションが参照または更新した資源は、そのトランザクションが終了するまで、他のトランザクションから更新されないことが保証されます。
動作環境ファイルのパラメタR_LOCKで行単位の排他が指定されていない場合に有効です。
SERIALIZABLEの場合の排他処理を以下に示します。
図2.6 SERIALIZABLEの場合の排他
(1) 利用者AがCOMMIT(ROLLBACK)終了するまで資源を占有します。
(2) 利用者Bは、利用者Aが資源を占有しているため、待ち状態となります。
(3) 利用者AがCOMMIT(ROLLBACK)するので、利用者Aの資源は解放されます。
(4) 利用者Aが資源を解放したので、利用者Bの更新が実行されます。このとき、資源を占有します。
(5) 利用者BがCOMMIT(ROLLBACK)するので、利用者Bの資源は解放されます。
あるトランザクションが参照または更新した資源は、そのトランザクションが終了するまで、他のトランザクションからの更新がないことが保証されます。
動作環境ファイルのR_LOCKパラメタで行単位の排他が指定されている場合に有効です。
排他の単位が行単位でかつREPEATABLE READが指定された場合は、該当のトランザクションがアクセスしていない行は占有しないので、同一トランザクション内で、同一のSQL文をくり返し実行しても、異なる集合が検索される場合があります。
REPEATABLE READの場合の排他処理を以下に示します。
図2.7 REPEATABLE READの場合の排他
(1) 利用者Aは、COL1がAの行を参照します。トランザクションが終了するまでこの行の集合を占有します。
(2) 利用者Bは、利用者Aが参照した行に対しては更新することができませんが、INSERT文で行を追加することはできます。
(3) 利用者Aが、再びCOL1がAの行を参照します。このとき前回参照した行に加えて、利用者Bが追加した行も検索されます。
あるトランザクションが更新した資源は、そのトランザクションが終了するまで、他のトランザクションから更新されないことが保証されます。しかし、以下のいずれかのSQL文で参照した資源に対しては、他のトランザクションから更新される可能性があります。
単一行SELECT文
更新可能性句に、FOR READ ONLYを指定したカーソルのOPEN文
トランザクションアクセスモードが読込み専用モードのときのOPEN文
したがって、同一トランザクション内でも、テーブル参照ごとに内容が異なる場合があります。
READ COMMITTEDの場合の排他処理を以下に示します。
図2.8 READ COMMITTEDの場合の排他
(1) 利用者Aが参照しているため(参照1)、この参照が終了するまで資源を占有します。
(2) 利用者Aが資源を解放するまで、利用者Bは更新を行えず、待ち状態となります。
(3) 利用者Aが参照終了(参照1)し、資源を解放します。
(4) 利用者Aが資源を解放したので、利用者Bの更新が実行されます。このとき、資源を占有します。
(5) 利用者Bが資源を解放するまで利用者Aは更新(更新)を行えず、待ち状態となります。
(6) 利用者Bの更新が終了します。
(7) 利用者Bがトランザクションを終了し、資源を解放します。
(8) 利用者Bが資源を解放したので、利用者Aの更新(更新)が実行されます。このとき、資源を占有します。
(9) 利用者Aが更新終了(更新)しますが、資源の占有は続きます。
(10) 利用者Aが参照(参照2)を行います。このとき検索される行は、利用者Bが更新した行を含みます。
(11) 利用者Aが参照(参照2)を終了しますが、資源の占有は続きます。
(12) 利用者Aがトランザクションを終了します。これによって資源が解放されます。
あるトランザクションが参照した資源は、他のトランザクションの参照および更新をまったく制限しません。また他のトランザクションが更新した資源も、トランザクションの終了を待たずに参照することができます。トランザクションが更新した資源は、トランザクション終了まで他のトランザクションの参照および更新を待たせます。
READ UNCOMMITTEDの場合の排他処理を以下に示します。
図2.9 READ UNCOMMITTEDの場合の排他
(1) 利用者Bは、更新処理(更新1)のため、COMMIT(ROLLBACK)終了するまで資源を占有します。
(2) 利用者Aは、資源を占有しないため、利用者Bが資源を占有していても、待ち状態にならずに参照処理(参照1)を行います。
(3) 利用者Aは利用者Bが資源を解放するまで更新を行えず、待ち状態となります。
(4) 利用者BがCOMMIT(ROLLBACK)します。利用者Bの資源は解放されます。
(5) 利用者Bが資源を解放したので、利用者Aの更新が実行されます。このとき、実際に更新した資源を占有します。
(6) 利用者Aが参照(参照2)を行います。このとき検索される行は、利用者Bが更新した行を含みます。
(7) 利用者Bは利用者Aが資源を解放するまで更新を行えず、待ち状態となります。
(8) 利用者Aが参照(参照2)を終了しますが、資源の占有は続きます。
(9) 利用者AがCOMMIT(ROLLBACK)します。
(10) 利用者Aが資源を解放したので、利用者Bの更新(更新2)が実行されます。このとき、資源を占有します。
(11) 利用者BがCOMMIT(ROLLBACK)します。
カーソルは、一般に、トランザクション終了時にクローズされます。しかし、次の場合、カーソルはクローズされません。
トランザクションの独立性水準指定がREAD COMMITTEDで、カーソル指定の更新可能性句がFOR READ ONLY の場合
カーソル宣言に、カーソルモード指定がある場合
以下に独立性水準指定にREAD COMMITTEDを指定し、更新可能性句にFOR READ ONLYを指定して実現する、トランザクションを超越するカーソル操作のSQL文の例を示します。
EXEC SQL DECLARE CSR1 CURSOR FOR ……(1) SELECT * FROM 取引先会社 WHERE 電話番号 LIKE :hcomp_word FOR READ ONLY; EXEC SQL SET TRANSACTION READ ONLY, ……(2) ISOLATION LEVEL READ COMMITTED; EXEC SQL OPEN CSR1; ……(3) EXEC SQL FETCH CSR1 INTO :hnumber,:hproduct,:hstock; ……(4) : EXEC SQL COMMIT WORK; ……(5) EXEC SQL FETCH CSR1 INTO :hnumber,:hproduct,:hstock; ……(6) : (データの終了) EXEC SQL CLOSE CSR1; ……(7)
(1) カーソル“CSR1”を宣言します。更新可能性句に“FOR READ ONLY”を設定します。
(2) トランザクションアクセスモードに“READ ONLY”を設定します。独立性水準に“READ COMMITTED”を設定します。
(3) カーソル“CSR1”をオープンします。
(4) 探索条件が真となる行にカーソルを位置づけ、その行を読み込みます。
(5) COMMITによりトランザクションを終了します。
(6) (5)でカーソルがクローズされないため、カーソルを位置づけることができます。
(7) データ終了後、カーソル“CSR1”をクローズします。
また、以下にカーソルモード指定によって実現する、トランザクションを超越するカーソル操作のSQL文の例を示します。
EXEC SQL DECLARE CSR1 CURSOR FOR ……(1) SELECT * FROM 取引先会社 WHERE 電話番号 LIKE :hcomp_word WITH OPTION LOCK_MODE(FREE LOCK),CURSOR_MODE(HOLD);
EXEC SQL OPEN CSR1; ……(2) EXEC SQL FETCH CSR1 INTO :hnumber,:hproduct,:hstock; ……(3) : EXEC SQL COMMIT WORK; ……(4) EXEC SQL FETCH CSR1 INTO :hnumber,:hproduct,:hstock; ……(5) : (データの終了) EXEC SQL CLOSE CSR1; ……(6)
(1) カーソル“CSR1”を宣言します。カーソルモード指定に“HOLD”を設定します。
(2) カーソル“CSR1”をオープンします。
(3) 探索条件が真となる行にカーソルを位置づけ、その行を読み込みます。
(4) COMMITによりトランザクションを終了します。
(5) (4)でカーソルがクローズされないため、カーソルを位置づけることができます。
(6) データ終了後、カーソル“CSR1”をクローズします。
トランザクションを超越するカーソルを使用する場合、カーソルのオープン中に、そのカーソルが参照する表の定義や格納構造定義が変更されると、次のトランザクションでFETCH文の実行が、SQLSTATE値が24000(カーソル不当)のエラーとなります。このエラーが発生した場合は、カーソルをクローズして、再度オープンするようにしてください。