非同期実行(FireDAC)

提供: Appmethod Topics
移動先: 案内検索

コマンドの操作(FireDAC) への移動

概要

プログラマは、ResourceOptions.CmdExecMode プロパティを使って、以下の 4 つの操作モードから選択できます。

モード 説明
amBlocking 呼び出し元スレッドと GUI は、アクションが完了するまでブロックされます。
amNonBlocking 呼び出し元スレッドは、アクションが完了するまでブロックされます。GUI はブロックされません。
amCancelDialog 呼び出し元スレッドと GUI は、アクションが完了するまでブロックされます。ダイアログが表示され、そこでアクションをキャンセルできます。
amAsync 呼び出しスレッドおよび GUI は、ブロックされます。The called method returns immediately.

アプリケーションでは、TFDCommand.State または TFDAdaptedDataSet.Command.State を調べて操作の状態(以下のいずれか)を確認できます。

状態 説明
csInactive コマンドが準備されていません。
csPrepared コマンドが準備されています。結果にはアクセスできません。
csExecuting コマンドが実行中です。
csOpen コマンドの実行が終了しました。結果セットはアクセス可能ですが、まだ全体は取得されていません。
csFetching 結果セットの取得が進行中です。
csAborting コマンド実行の中止が進行中です。

以下に例を示します。

FDQuery1.ResourceOptions.CmdExecMode := amAsync;
FDQuery1.Open;
while FDQuery1.Command.State = csExecuting do begin
  // do something while query is executing
end;

amCancelDialog モードでは、長時間かかる操作の場合は、そのことがユーザーに通知され、ユーザーが次のような TFDGUIxAsyncExecuteDialog コンポーネントを使ってその操作をキャンセルできます。

AsyncExecuteDialogPicture.png

このダイアログ コンポーネントを使用するには、それをフォームにドロップします。それ以上のセットアップは不要です。操作モードと通知イベントの詳細については、ResourceOptions.CmdExecMode プロパティの説明を参照してください。



非同期の開始と取得

アプリケーションでクエリを非同期的に開始する必要があり(amAsync モード)、かつ、そのクエリが TDataSource を使って GUI にバインドされている場合、クエリを開始する前にその TDataSource をクエリからいったん接続解除し、クエリを開始した後に接続し直す必要があります。以下に例を示します。

procedure TForm1.FDQuery1BeforeOpen(DataSet: TDataSet);
begin
  DataSource1.DataSet := nil;
end;

procedure TForm1.FDQuery1AfterOpen(DataSet: TDataSet);
begin
  DataSource1.DataSet := FDQuery1;
  FDQuery1.ResourceOptions.CmdExecMode := amBlocking;
end;

FDQuery1.BeforeOpen := FDQuery1BeforeOpen;
FDQuery1.AfterOpen := FDQuery1AfterOpen;
FDQuery1.ResourceOptions.CmdExecMode := amAsync;
FDQuery1.Open;

これは、amCancelDialog が使用される場合は不要です。また、GUI を使った取得は、amAsync モードでは実行できません。クエリを開始し、大量の結果セットを非同期的に取得するには、FetchOptions.Mode を fmAll に設定します。その場合、どちらの操作も単一のバックグラウンド タスクとして実行されます。

メモ: この処理は、双方向データセットを使用する場合にのみ有効です。

Firebird クエリを非同期的に実行するには、そのクエリに別個のトランザクションを使用します。

長時間かかる操作のキャンセル

プログラムでは、ResourceOptions.CmdExecTimeout プロパティを使って、データ アクセス操作のタイムアウトを指定できます。操作の実行に必要な時間が指定の時間を上回る場合は、実行がキャンセルされ、例外が発生します。コマンドのタイムアウトを捕捉するには、次のようなコードを使用します。

try
  // set timeout to 5 seconds
  FDQuery1.ResourceOptions.CmdExecTimeout := 5000;
  FDQuery1.ExecSQL;
except
  on E: EFDDBEngineException do
    if E.Kind = ekCmdAborted then
      ; // command is aborted
end;

あるいは、アプリケーションでは、他のスレッドからデータセットまたはコマンドの AbortJob メソッドを呼び出すことで操作の実行をキャンセルできますし、接続の AbortJob メソッドを呼び出して、その接続を通じて実行されているすべての操作をキャンセルすることもできます。

メモ: すべての FireDAC ドライバおよび DBMS で実行のキャンセルがサポートされているわけではありません。また、DBMS で一部の非常に重要な操作が実行されている場合は、キャンセルをすぐに実行することはできません。サポートされている組み合わせの一覧を以下の表に示します。
DBMS メモ
Advantage
IBM DB2
Firebird バージョン 2.5 以降
Informix
InterBase バージョン 7.0 以降
MySQL バージョン 5.0 以降
Oracle
PostgreSQL
SQL Anywhere
SQL SERVER
SQLite
Teradata Database

複数の非同期クエリ

複数の非同期クエリの同時実行は、マルチスレッド処理の一般原則のために、FireDAC ではサポートされていません。この問題を回避するには、以下の選択肢を検討します。

  • いくつかのクエリを 1 つのストアド プロシージャにまとめ、そのプロシージャを非同期的に呼び出す。
  • 同時に実行される非同期クエリごとに専用の接続を使用する。
  • 前の非同期クエリが完了してから、次の非同期クエリを起動する。それには、AfterOpen および AfterExecute イベント ハンドラを使用します。
  • アプリケーションでそれ専用のスレッドを作成し、それらのスレッドで DB タスクを実行する。