トランザクションの管理

提供: RAD Studio
移動先: 案内検索

データベースへの接続:インデックス への移動


トランザクションとは、データベース内の 1 つまたは複数のテーブルに対して実行されるアクションの集合で、すべてが成功しなければコミットされない(永続化されない)もののことです。 グループの中のアクションが 1 つでも失敗すると、すべてのアクションがロールバックされます(元に戻されます)。 トランザクションを使用することで、トランザクションを構成するアクションのいずれかの完了に問題があった場合、データベースが不整合の状態のままで放置されないことが保証されます。

たとえば、銀行アプリケーションにおいては、ある口座から別の口座への資産の振替は、トランザクションで保護したいオペレーションの 1 つでしょう。 もし一方の口座の残高を減少させたのち、もう一方の口座の残高を増加させることに失敗したら、トランザクションをロールバックさせて、データベースが正しい合計残高を反映させたままであるようにします。

トランザクションの管理は、SQL コマンドをデータベースに直接送信することで常に可能です。 大抵のデータベースは独自のトランザクション管理モデルを提供している一方で、トランザクションをまったくサポートしていないものもあります。 サポートしているサーバーにおいて、独自のトランザクション管理を直接コードで記述し、たとえばスキーマ キャッシュなど、特定のデータベース サーバーで上級のトランザクション管理機能を利用したい場合もあるでしょう。

上級のトランザクション管理機能を使用する必要がない場合、SQL コマンドを明示的に送信しなくても、接続コンポーネントが、トランザクション管理のためのメソッドとプロパティのセットを提供しています。 これらのプロパティやメソッドを利用することで、データベース サーバーがトランザクションをサポートしている限り、それのどのタイプを使用しても、アプリケーションをカスタマイズする必要がない、という利点があります。 (BDE はまた、ローカル テーブルに対して制限付きのトランザクション サポートを提供しており、サーバー側のトランザクション サポートはありません。 BDE を使用しない場合、トランザクションをサポートしないデータベース上でトランザクションを開始使用とすると、接続コンポーネントが例外を発生させます。)

警告: データセット プロバイダ コンポーネントが更新を適用すると、どの更新に対してもトランザクションを暗黙的に生成します。このため、明示的に開始したトランザクションがいずれも、プロバイダによって生成されたトランザクションと競合しないように注意してください。

トランザクションを開始する

トランザクションを開始すると、データベースに対して読み書きを行うそれ以降の文はすべて、そのトランザクションのコンテキスト内で発生し、それはトランザクションが明示的に終了させられるまで、または(トランザクションがオーバーラップする場合)、別のトランザクションが開始されるまで続きます。各文は、1 つのグループの一部と考えられます。変更が正常にデータベースに対してコミットされるか、さもなければ、そのグループ内で行われたすべての変更が元に戻されなければなりません。

トランザクションが処理されている間、データベース テーブル内のデータのビューは、トランザクション分離レベルによって決定されます。

TADOConnection の場合、トランザクションは BeginTrans メソッドを呼び出すことで開始されます。

 Level := ADOConnection1.BeginTrans;

BeginTrans は、開始されたトランザクションのネスト レベルを返します。ネスト トランザクションは、ほかの親のトランザクション内に入れ子になったトランザクションです。サーバーがトランザクションを開始した後、ADO 接続は OnBeginTransComplete イベントを受け取ります。

TDatabase の場合、代わりに StartTransaction メソッドを使用します。TDataBase は、ネスト トランザクションまたはオーバーラップしたトランザクションはサポートしていません。別のトランザクションの実行中に、TDatabase コンポーネントの StartTransaction メソッドを呼び出すと、例外が発生します。StartTransaction の呼出しを回避するためには、InTransaction プロパティをチェックします。

 if not Database1.InTransaction then
   Database1.StartTransaction;

TSQLConnection はまた、StartTransaction メソッドも使用しますが、そこではさらに制御可能なバージョンを使用します。特に StartTransaction はトランザクション ディスクリプタをパラメータに取り、それにより、同時に複数のトランザクションを管理し、1 つのトランザクションごとにトランザクション分離レベルを指定することができます。同時に複数のトランザクションを管理するには、トランザクション ディスクリプタ TransactionID フィールドを、一意の値に設定します。TransactionID は、それが一意である(現在実行中の他のトランザクションと競合しない)限り、自由に選択した値にできます。サーバーによっては、TSQLConnection によって開始されたトランザクションは、ネストできたり( ADO 使用時にはできる)、オーバーラップさせたりできます。

 var
   TD: TTransactionDesc;
 begin
   TD.TransactionID := 1;
   TD.IsolationLevel := xilREADCOMMITTED;
   SQLConnection1.StartTransaction(TD);

デフォルトでは、オーバーラップしたトランザクションでは、最初のトランザクションが、2 つ目のトランザクションが開始したときに非アクティブになります。ただし、最初のトランザクションをコミットするかロールバックするかを、後に延期することは可能です。TSQLConnection を InterBase データベースと使用する場合、特定のアクティブ トランザクションを持つアプリケーションで、各データセットを識別するには、その IsolationLevel プロパティを使用します。つまり、2 つ目のトランザクションを開始した後、単純にデータセットを希望するトランザクションと関連づけることで、両方のトランザクションを同時に処理し続けることができます。

メモ: TADOConnection とは異なり、TSQLConnectionTDatabase は、トランザクションが開始した際にイベントを受け取りません。

InterBase Express は、TSQLConnection よりも高度な制御を提供しており、そのために、接続コンポーネントを使用してトランザクションを開始するのではなく、別個のトランザクション コンポーネントを使用します。しかしながら、TIBDatabase を使用して、デフォルトのトランザクションを開始することも可能です。

 if not IBDatabase1.DefaultTransaction.InTransaction then
   IBDatabase1.DefaultTransaction.StartTransaction;

2 つの別個のトランザクション コンポーネントを使用すると、トランザクションをオーバーラップさせることができます。各トランザクション コンポーネントには、パラメータのセットがあり、それにより、トランザクションを設定することができます。それらでは、トランザクション分離レベルを、トランザクションの他のプロパティと同様、指定することができます。

トランザクションを終了させる

理想的には、トランザクションは必要とする間のみ持続するべきです。トランザクションがアクティブである時間が長いほど、より多くのユーザーがデータベースにアクセスし、より多くの並列トランザクションや同時トランザクションが、そのトランザクションのライフタイムの間に発生し終わり、自分のトランザクションで変更をコミットしようとする際、別のトランザクションと競合する可能性が上がります。

トランザクションを構成するアクション群がすべて成功すると、トランザクションをコミットすることで、データベースでの変更を永続的なものにすることができます。TDatabase の場合、トランザクションは Commit メソッドを使用して行います。

 MyOracleConnection.Commit;

TSQLConnection の場合も、Commit メソッドを使用しますが、StartTransaction メソッドに指定したトランザクション ディスクリプタを渡すことで、コミットするトランザクションを指定しなければなりません:

 MyOracleConnection.Commit(TD);

TIBDatabase の場合、トランザクション オブジェクトは Commit メソッドを使用してコミットします:

 IBDatabase1.DefaultTransaction.Commit;

TADOConnection の場合、トランザクションは CommitTrans メソッドを使用してコミットします:

 ADOConnection1.CommitTrans;

メモ: ネスト トランザクションをコミットできるのは、親トランザクションがロール バックした場合に、その変更を後からロール バックするためのみです。

トランザクションが正常にコミットされたら、ADO 接続コンポーネントは OnCommitTransComplete イベントを受け取ります。他の接続コンポーネントは、同様のイベントを受け取りません。

並列トランザクションをコミットするための呼出しは、通常、try...except 文の中で試行されます。それにより、トランザクションが正常にコミットできなかった場合、 except ブロックを使用してエラーを処理し、オペレーションを再試行したり、トランザクションをロールバックすることができます。

トランザクションの一部となっている変更を行った場合、または、トランザクションのコミットを試みた際にエラーが発生した場合、トランザクションを構成するすべての変更を破棄することができます。これらの変更を破棄することを、トランザクションをロールバックする、と言います。

TDatabase の場合、トランザクションは Rollback メソッドを呼び出すことで、ロールバックされます:

 MyOracleConnection.Rollback;

TSQLConnection の場合も、Rollback メソッドを使用しますが、StartTransaction メソッドに指定したトランザクション ディスクリプタを渡すことで、ロールバックするトランザクションを指定しなければなりません:

 MyOracleConnection.Rollback(TD);

TIBDatabase の場合、トランザクション オブジェクトは Rollback メソッドを呼び出すことで、ロールバックされます:

 IBDatabase1.DefaultTransaction.Rollback;

TADOConnection の場合、トランザクションは RollbackTrans メソッドを呼び出すことで、ロールバックされます:

 ADOConnection1.RollbackTrans;

トランザクションが正常にロールバックされたら、ADO 接続コンポーネントは OnRollbackTransComplete イベントを受け取ります。 他の接続コンポーネントは、同様のイベントを受け取りません。

並列トランザクションをロールバックする呼出しは、通常次で発生します:

  • データベース エラーからリカバリできない場合には、例外処理コードで。
  • ユーザーが [キャンセル] ボタンをクリックしたような場合には、ボタンやメニューのイベント コードで。

関連項目