Symfoware Server アプリケーション開発ガイド(埋込みSQL編) - FUJITSU - |
目次 索引 |
第2章 アプリケーションの設計 | > 2.4 トランザクションと排他制御 |
アプリケーションがデータベースをアクセスする場合の排他制御は、トランザクション単位に行われます。したがって、いくつかのアプリケーションを並行して実行した場合、データ操作の順序によっては、以下に示すようにデッドロックが発生します。このため、アプリケーションには、デッドロックの対処が必要になる場合があります。
以下の順序で処理が行われるとデッドロックが発生します。
(1) APL1が表T1に対して参照ロックを獲得します((5)のCOMMITまでロックを保持します)。
(2) APL2が表T2に対して参照ロックを獲得します((6)のCOMMITまでロックを保持します)。
(3) APL1は表T1の参照を終え、表T2を更新するために表T2に対して更新ロックを獲得しようとしますが、表T2にはAPL2が参照ロックを獲得しているため待たされます(表T1はAPL1がロックを獲得したままとなります)。
(4) APL2は表T2の参照を終え、表T1を更新するために表T1に対して更新ロックを獲得しようとしますが、表T1にはAPL1が参照ロックを獲得しているため待たされます(表T2はAPL2がロックを獲得したままとなります)。
APL1とAPL2は、互いに相手方のトランザクションが終了するのを待たされる状態になります。ところが、APL1の(5)のCOMMIT、およびAPL2の(6)のCOMMITが実行されないために、どちらのアプリケーションも実行できなくなります。この状態がデッドロックです。
デッドロックはSymfoware/RDBが自動的に検出します。Symfoware/RDBがデッドロックを検出すると、複数のトランザクションのうちの1つのトランザクションを取り消して、アプリケーションにエラー復帰します。このとき、SQLSTATEには“トランザクションの直列化に失敗”を表す例外コードが設定されます。
デッドロックの発生を通知されたアプリケーションでは、一般にデッドロックが発生したトランザクションの再実行を試みます。トランザクションを再実行するには、トランザクションを開始した文の直前に制御を移します。ただし、SQL文で使用するホスト変数をトランザクションの処理途中で変更している場合には、その値をトランザクションの開始時点に戻す必要があります。
以下に、図:デッドロックの発生例のAPL1が、トランザクションの再実行を行う場合の処理の流れを示します。
カーソル宣言の更新可能性句を省略しそのカーソルが更新可能な場合、そのカーソルで更新を行うことができます。この場合、以下に示す操作を行うと、デッドロックが起きることがあります。
(1) 利用者Aは、更新可能性句を省略したカーソルのOPEN文を実行します。これにより、表T1で参照した部分に対して共有モードで占有します。
(2) 利用者Bも同じく、更新可能性句を省略したカーソルのOPEN文を実行します。これにより、表T1で参照した部分に対して共有モードで占有します。
(3) 利用者Aが表T1で参照した部分を更新するために、非共有モードで占有しようとしますが、表T1は利用者Bが共有モードで占有しているため待たされます(表T1は利用者Aが共有モードで占有したままとなります)。
(4) 利用者Bが表T1で参照した部分を更新するために、更新ロックを獲得しようとしますが、表T1は利用者Aが共有モードで占有しているため待たされます(表T1は利用者Aが共有モードで占有したままとなります)。
カーソル操作でデッドロックを起こさないため、更新系のSQL文を実行する場合には、カーソル宣言の占有モード指定に、EXCLUSIVE LOCKを指定してください。
(1) 利用者Aは、EXCLUSIVE LOCKで参照し、COMMIT(ROLLBACK)終了するまで資源を占有します。
(2) 利用者Bは、EXCLUSIVE LOCKで参照を行うため、利用者Aが資源を解放するまで参照を行えず、待ち状態となります。
(3) 利用者Aは、他のアプリケーションに待たされることなく更新処理を行います。
(4) 利用者AがCOMMIT(ROLLBACK)します。利用者Aの資源は解放されます。
(5) 利用者Aが資源を解放したので、利用者Bの参照が実行されます。この時、資源を占有します。
(6) 利用者Bの更新が実行されます。
(7) 利用者BがCOMMIT(ROLLBACK)します。
目次 索引 |