トランザクションは、あるプロセスにおいてデータベースに対して行われる一連の関連したデータ更新です。トランザクションは、そのトランザクションが受け入れられるまで、データベースに恒久的には保存されません。キャンセルされたり、他の外部的な原因でトランザクションが完了できなかった場合には、更新処理の結果は保存されません。
トランザクション処理中に、プロセス内でデータベースのデータに対して行った更新はすべて、一時的なバッファにローカルで保存されます。トランザクションがVALIDATE TRANSACTIONで受け入れられた時点で、更新されたデータが恒久的に保存されます。トランザクションがCANCEL TRANSACTIONでキャンセルされた場合、更新されたデータは保存されません。すべての場合において、カレントセレクションやカレントレコードは、トランザクション管理コマンドでは更新されません。
バージョン11以降、4Dはネストされたトランザクション、つまり幾つかの階層レベルにあるトランザクションをサポートしています。認められているサブトランザクションの数は無限です。 Transaction levelコマンドを使用して、コードが実行されている現在のトランザクションレベルを調べることができます。
ネストされたトランザクションを使用するとき、各サブトランザクションの結果は、高レベルトランザクションの受け入れまたはキャンセルにより異なります。高レベルトランザクションが受け入れられると、サブトランザクションの結果が承認されます (受け入れまたはキャンセル) 。一方、高レベルトランザクションがキャンセルされると、それぞれの結果に関係なく、すべてのサブトランザクションがキャンセルされます。
ネストされたトランザクションは、4Dの以前のバージョンで構築されたデータベース上で誤動作を招きます。そのため、変 換されたデータベースではデフォルトで無効になっています (トランザクションは単一レベルに制限されています) 。変換されたデータベース上で複数レベルのトランザクションを利用したい場合、アプリケーションの環境設定にあるアプリケーション/互換ページの "トランザクションのネストを許可する" オプションをチェックして明確に指示しなければなりません。
こ のオプションは変換されたデータベース上にしか表示されません。これは、デフォルトでチェックされていません。この設定は各データベースに固有のもので す。4DのSQLエンジンで実行されたトランザクションには効果がありません。SQLトランザクションはいつもマルチレベルです。
この例題は、簡単な請求書システムです。請求書の明細は、 [Invoice Lines] テーブルに格納されています。[Invoice Lines]Invoice IDフィールドは[Invoices]Invoice IDフィールドとリレートしています。請求書が追加されると、重複不可のIDがSequence numberコマンドを使用して計算されます。 [Invoices] テーブルと [Invoice Lines] テーブルのリレートは1対nの自動リレートになっており、サブフォームにあるリレート値自動代入チェックボックスがチェックされています。
[Invoice Lines] テーブルと [Parts] テーブルのリレートは、マニュアルリレートです。
![](http://doc.tmp.4d.fr/picture/35829/pict35829.ja.png)
ユーザは請求書を入力する場合に、以下のような動作を実行しなければなりません。
- [Invoices] テーブルにレコードを追加する
- [Invoice Lines] テーブルにレコードを幾つか追加する
- 請求書にリストされた各部品の [Parts]In Warehouseフィールドを更新する
この例題は、トランザクションの使用が必要になる典型的なシーンの1つです。処理中に必ずこれらのレコードをすべて保存できるということや、または レコードが追加されない場合やレコードが更新されない場合は、トランザクションをキャンセルできるということを確認する必要があります。つまり、リレート されたレコードを保存しなくてはなりません。
トランザクションを使用しない場合には、データベースの理論的なデータの整合性を保証することはできません。例えば、 [Parts] テーブルのレコードがロックされていると、 [Parts]In Warehouseフィールドに格納されている数量を更新することはできません。したがって、このフィールドは理論上、正しいものではなくなります。つま り、販売した部品の合計と倉庫内に残っている在庫数が、レコードに入力したオリジナルの数量と等しくならなくなります。こういう状況を避けるために、トラ ンザクションを使用します。
トランザクションを使って、データ入力を実行する方法は幾つかあります。
1. START TRANSACTION、VALIDATE TRANSACTIONとCANCEL TRANSACTIONトランザクションコマンドを使用してトランザクションを独自に管理できます。例えば、以下のように記述します。
2. データ入力実行中のレコードロックを減らすには、フォームメソッド内からトランザクションを管理し、必要になった時にだけREAD WRITE状態にしてアクセスすることができます。
サブフォームに [Invoice Lines] リレートテーブルを持つ [Invoices] テーブルの入力フォームを使ってデータ入力を行います。このフォームには動作なしボタン属性を持つbCancelとbOKの2つのボタンがあります。
メソッドは以下のようになります。
データ入力中は [Parts] テーブルが読み込み専用の状態になっていることに注意してください。読み/書き状態はデータ入力が有効な場合にのみ利用できます。
[Invoices] 入力フォームから開始されるトランザクションを以下に示します。
bCancelボタンをクリックすると、トランザクションはもちろんのことデータ入力も取り消す必要があります。
以下にbCancelボタンのオブジェクトメソッドを示します。
bValidateボタンをクリックすると、トランザクションはもちろんのことデータ入力も受け付ける必要があります。以下にbOKボタンのオブジェクトメソッドを示します。
このコードでは、ボタンのクリックに関係なく、CANCEL コマンドを実行します。新しいレコードはACCEPT ボタンを呼び出しても受け入れられず、SAVE RECORDコマンドで受け入れられます。さらに、SAVE RECORDコマンドがVALIDATE TRANSACTIONコマンドの直前に呼び出されている点に注意してください。したがって、[Invoices] テーブルのレコードを保存するということは、実際にはトランザクションの一部であるということです。ACCEPT コマンドを呼び出してレコードを受け入れることもできますが、その場合、[Invoices] レコードが保存される前にトランザクションが受け入れられてしまいます。つまり、レコードはトランザクションの外で保存されてしまいます。
必要に応じ、データベースを独自にカスタマイズすることができます。最後の例題では、[Parts] テーブルのロックレコードの処理をさらに開発することも可能です。