4D v16.3

トランザクションを使用する

ホーム

 
4D v16.3
トランザクションを使用する

トランザクションを使用する  


 

 

トランザクションは、あるプロセスにおいてデータベースに対して行われる一連の関連したデータ更新です。トランザクションは、そのトランザクション が受け入れられるまで、データベースに恒久的には保存されません。キャンセルされたり、他の外部的な原因でトランザクションが完了できなかった場合には、 更新処理の結果は保存されません。

トランザクション処理中に、プロセス内でデータベースのデータに対して行った更新はすべて、一時的なバッファにローカルで保存されます。トランザクションがVALIDATE TRANSACTIONで受け入れられた時点で、更新されたデータが恒久的に保存されます。トランザクションがCANCEL TRANSACTIONでキャンセルされた場合、更新されたデータは保存されません。すべての場合において、カレントセレクションやカレントレコードは、トランザクション管理コマンドでは更新されません。

4Dではネストされたトランザクション、つまり幾つかの階層レベルにあるトランザクションをサポートしています。認められているサブトランザクションの数は無限です。Transaction levelコマンドを使用して、コードが実行されている現在のトランザクションレベルを調べることができます。
ネ ストされたトランザクションを使用するとき、各サブトランザクションの結果は、高レベルトランザクションの受け入れまたはキャンセルにより異なります。高 レベルトランザクションが受け入れられると、サブトランザクションの結果が承認されます (受け入れまたはキャンセル) 。一方、高レベルトランザクションがキャンセルされると、それぞれの結果に関係なく、すべてのサブトランザクションがキャンセルされます。

注: 互換性のため、ネストされたトランザクションは、v11以前のバージョンから変換されたデータベースにおいては、デフォルトで無効化されています(互換性ページを参照)。

4Dでは4Dコードの中においてトランザクションを一時停止・再開させる機能を備えています。トランザクションがsuspended(一時停止)のときには、トランザクションとは別個にオペレーションを実行することができ、そのトランザクションのresume(再開)後に通常通りそれを評価あるいはキャンセルすることができます。トランザクションが一時停止中にできる事としては、具体的には以下の様なものがあります:

  • レコードをトランザクション外で作成あるいは変更する(例えば請求書の番号カウンターを一つ増加する、など)
  • 他のトランザクションを開始・一時停止、あるいは閉じる

この点についてのより詳細な情報については、トランザクションの停止を参照して下さい。

この例題は、簡単な請求書システムです。請求書の明細は、 [Invoice Lines] テーブルに格納されています。[Invoice Lines]Invoice IDフィールドは[Invoices]Invoice IDフィールドとリレートしています。請求書が追加されると、重複不可のIDがSequence numberコマンドを使用して計算されます。 [Invoices] テーブルと [Invoice Lines] テーブルのリレートは1対nの自動リレートになっており、サブフォームにあるリレート値自動代入チェックボックスがチェックされています。

[Invoice Lines] テーブルと [Parts] テーブルのリレートは、マニュアルリレートです。

ユーザは請求書を入力する場合に、以下のような動作を実行しなければなりません。

  • [Invoices] テーブルにレコードを追加する
  • [Invoice Lines] テーブルにレコードを幾つか追加する
  • 請求書にリストされた各部品の [Parts]In Warehouseフィールドを更新する

この例題は、トランザクションの使用が必要になる典型的なシーンの1つです。処理中に必ずこれらのレコードをすべて保存できるということや、または レコードが追加されない場合やレコードが更新されない場合は、トランザクションをキャンセルできるということを確認する必要があります。つまり、リレート されたレコードを保存しなくてはなりません。

トランザクションを使用しない場合には、データベースの理論的なデータの整合性を保証することはできません。例えば、 [Parts] テーブルのレコードがロックされていると、 [Parts]In Warehouseフィールドに格納されている数量を更新することはできません。したがって、このフィールドは理論上、正しいものではなくなります。つま り、販売した部品の合計と倉庫内に残っている在庫数が、レコードに入力したオリジナルの数量と等しくならなくなります。こういう状況を避けるために、トラ ンザクションを使用します。

トランザクションを使って、データ入力を実行する方法は幾つかあります。

1. START TRANSACTIONVALIDATE TRANSACTIONCANCEL TRANSACTIONトランザクションコマンドを使用してトランザクションを独自に管理できます。例えば、以下のように記述します。

 READ WRITE([Invoice Lines])
 READ WRITE([Parts])
 FORM SET INPUT([Invoices];"Input")
 Repeat
    START TRANSACTION
    ADD RECORD([Invoices])
    If(OK=1)
       VALIDATE TRANSACTION
    Else
       CANCEL TRANSACTION
    End if
 Until(OK=0)
 READ ONLY(*)

2. データ入力実行中のレコードロックを減らすには、フォームメソッド内からトランザクションを管理し、必要になった時にだけREAD WRITE状態にしてアクセスすることができます。

サブフォームに [Invoice Lines] リレートテーブルを持つ [Invoices] テーブルの入力フォームを使ってデータ入力を行います。このフォームには動作なしボタン属性を持つbCancelbOKの2つのボタンがあります。
メソッドは以下のようになります。

 READ WRITE([Invoice Lines])
 READ ONLY([Parts])
 FORM SET INPUT([Invoices];"Input")
 Repeat
    ADD RECORD([Invoices])
 Until(bOK=0)
 READ ONLY([Invoice Lines])

データ入力中は [Parts] テーブルが読み込み専用の状態になっていることに注意してください。読み/書き状態はデータ入力が有効な場合にのみ利用できます。

[Invoices] 入力フォームから開始されるトランザクションを以下に示します。

 Case of
    :(Form event=On Load)
       START TRANSACTION
       [Invoices]Invoice ID:=Sequence number([Invoices]Invoice ID)
    Else
       [Invoices]Total Invoice:=Sum([Invoice Lines]Total line)
 End case

bCancelボタンをクリックすると、トランザクションはもちろんのことデータ入力も取り消す必要があります。
以下にbCancelボタンのオブジェクトメソッドを示します。

 Case of
    :(Form event=On Clicked)
       CANCEL TRANSACTION
       CANCEL
 End case

bValidateボタンをクリックすると、トランザクションはもちろんのことデータ入力も受け付ける必要があります。以下にbOKボタンのオブジェクトメソッドを示します。

 Case of
    :(Form event=On Clicked)
       $NbLines:=Records in selection([Invoice Lines])
       READ WRITE([Parts]`[Parts] テーブルに対して、読み/書き状態に変更する
       FIRST RECORD([Invoice Lines]) `最初の明細で開始する
       $ValidTrans:=True `すべてOKであると仮定する
       For($Line;1;$NbLines`各明細に対して
          RELATE ONE([Invoice Lines]Part No)
          OK:=1 `続行したいと仮定する
          While(Locked([Parts]) & (OK=1)) `読み/書き状態でレコードを取得してみる
             CONFIRM("The Part "+[Invoice Lines]Part No+" is in use. Wait?")
             If(OK=1)
                DELAY PROCESS(Current process;60)
                LOAD RECORD([Parts])
             End if
          End while
          If(OK=1)
  `倉庫の数量を更新する
             [Parts]In Warehouse:=[Parts]In Warehouse-[Invoice Lines]Quantity
             SAVE RECORD([Parts]`レコードを保存する
          Else
             $Line:=$NbLines+1 `ループを抜ける
             $ValidTrans:=False
          End if
          NEXT RECORD([Invoice Lines]) `次の明細へ移動する
       End for
       READ ONLY([Parts]` テーブルを読み込み専用状態にする
       If($ValidTrans)
          SAVE RECORD([Invoices]) `送り状レコードを保存する
          VALIDATE TRANSACTION `すべてのデータベースの修正を受け入れる
       Else
          CANCEL TRANSACTION `すべてキャンセルする
       End if
       CANCEL `フォームを抜ける
 End case

このコードでは、ボタンのクリックに関係なく、CANCEL コマンドを実行します。新しいレコードはACCEPT ボタンを呼び出しても受け入れられず、SAVE RECORDコマンドで受け入れられます。さらに、SAVE RECORDコマンドがVALIDATE TRANSACTIONコマンドの直前に呼び出されている点に注意してください。したがって、[Invoices] テーブルのレコードを保存するということは、実際にはトランザクションの一部であるということです。ACCEPT コマンドを呼び出してレコードを受け入れることもできますが、その場合、[Invoices] レコードが保存される前にトランザクションが受け入れられてしまいます。つまり、レコードはトランザクションの外で保存されてしまいます。

必要に応じ、データベースを独自にカスタマイズすることができます。最後の例題では、[Parts] テーブルのロックレコードの処理をさらに開発することも可能です。



参照 

CANCEL TRANSACTION
In transaction
START TRANSACTION
VALIDATE TRANSACTION

 
プロパティ 

プロダクト: 4D
テーマ: トランザクション

 
履歴 

変更: 4D v15 R4

 
ARTICLE USAGE

ランゲージリファレンス ( 4D v16)
ランゲージリファレンス ( 4D v16.1)
ランゲージリファレンス ( 4D v16.2)
ランゲージリファレンス ( 4D v16.3)