トランザクションの管理は、単純に処理を確定するか取り消すかといった問題ではありません。アプリケーションのレベルでは、その仕様やユーザーインターフェイスと絡んできます。
- 自動的なトランザクション -
前回紹介したように、レコードの削除(DELETE命令)や更新(UPDATE命令)などデータベースを書き換える処理を行う場合、同時アクセスによる競合を防ぐためにトランザクションは自動的に開始~終了されます。
但し、自動的なトランザクションでは、SQL命令を発行した後で自動的に確定(コミット)されてしまうため、ロールバックによる処理の取り消しは行えません。一般的な(エラーの発生やユーザーの都合によって処理を取り消す必要のない)処理では、こういった自動的なトランザクション管理に任せてしまって構いません。
この場合、自動的なトランザクションは単にテーブルやレコードのロック機能を提供することになります。
- 明示的トランザクションの必要性 -
これとは別に、BEGIN TRANSACTION、COMMIT TRANSACTION、ROLLBACK TRANSACTIONといった明示的なトランザクション管理の命令が用意されているのには理由があります。《競合や処理中のエラーによる矛盾の発生》が懸念される場合や《ユーザーの都合による処理の中断》が想定される場合に、明示的なトランザクション管理が意味を持つのです。
競合による矛盾については、前回、例で示したようなマスターテーブルに対する複数クライアントからの同時アクセスが典型でしょう。
エラーの問題は、意外と意識されません。プログラマーは、意図した処理(SQLによるデータベースの変更処理)が難なく進行すると考えがちです。確かに、作成しているアプリケーションの中では矛盾なく処理されることが保証されるかもしれません(あくまで、確実な仕様設計がなされた場合に限りますが)。
しかし、複数のコンピュータがデータベースにアクセスするクライアント・サーバー方式のネットワークやWeb環境では、1つのアプリケーション内で予測することの不可能な事態が発生しないとも限りません。そのような場合、発行したSQLがエラーを返すこともあり得ます。
- 条件判断と分岐で対処 -
SQLを発行してDBMSからエラーが返ってきた場合、アプリケーションを開発しているプログラミング言語のエラー処理ではなく、SQLのエラー処理で対処することになります。一般的には、コンポーネントが受け取ったDBMSのエラーをトラップし、その中で処理を強行するのか取り消すのかを判断します。
トランザクション管理は、こういった場合に役立ちます。エラーが返ってきた場合に問題の起きることが予測される処理では、その直前に明示的なトランザクション管理を開始し、万一エラーが返ってきたら処理を取り消してユーザーにその旨を報告します。そして、エラーがなければトランザクションを確定します。
つまり、以下のような構造です。
BEGIN TRANSACTION
:
競合しそうなSQL命令
:
If エラー発生
ROLLBACK TRANSACTION ---- 処理を取消
Else
COMMIT TRANSACTION ------ 処理を確定
End If
- 元に戻せることが重要 -
こういった処理を無闇に使用する必要はありません。例えば、マスターテーブルの保守処理が確実に1台の端末からのみ実行されることが明白であれば、自動的なトランザクション管理に任せても大丈夫です。
アプリケーション側のフレキシブルなトランザクション管理を考える以前に、業務全体を見渡した上での時間帯によるアクセス制限など、ユーザーによる『人的な管理』を重視しなければなりません(逆に言えば、人的なファクターによる問題をすべてコンピュータ上で解決しようという発想自体が問題です)。
複数の端末から1つのテーブルに対して変更処理が行われるような場合──例えば受注処理や、それに関連した在庫管理処理では、明示的なトランザクションの管理が有効です。1件の受注を処理している間は受注された商品に関連するレコードをロックしておき、受注が確定(コミット)した段階で解除します。万一受注が取り消されたらロールバックすることになります。
また、商品の入荷や廃棄などの処理を行っている間は対象商品のレコードをロックし、処理が確定して在庫数が明確になった時点でそれを解除、作業の都合で処理を取りやめる場合にはロールバック……といった感じです。
このように、トランザクションの管理は業務システム全体を見渡し、エラーの発生や突発的で予測不能な理由による取り消しなどで、データベースの内容を《処理直前の状態に戻す必要のある場合だけ》を対象とするのがよいでしょう。それ以外は自動的なトランザクション管理に頼った方が効率的です。
|
|
|