SQL Server では、アプリケーションで非同期データベース操作を実行できます。 非同期処理を使用すると、メソッドは呼び出し元のスレッドでブロックすることなく、すぐに戻ることができます。 これにより、開発者が明示的にスレッドを作成したり、同期を処理したりする必要なしに、マルチスレッドの機能と柔軟性の多くを実現できます。 アプリケーションは、データベース接続を初期化するとき、またはコマンドの実行から結果を初期化するときに、非同期処理を要求します。
データベース接続を開く/閉じる
SQL Server Native Client OLE DB プロバイダーを使用する場合、データ ソース オブジェクトを非同期的に初期化するように設計されたアプリケーションでは、 IDBInitialize::Initialize を呼び出す前に、DBPROP_INIT_ASYNCH プロパティにDBPROPVAL_ASYNCH_INITIALIZE ビットを設定できます。 このプロパティを設定すると、操作がすぐに完了した場合は S_OK を使用して Initialize の呼び出しから直ちに返されます。初期化が非同期的に続行されている場合はDB_S_ASYNCHRONOUS。 アプリケーションは、データ ソース オブジェクトの IDBAsynchStatus または ISSAsynchStatusインターフェイスを照会し、 IDBAsynchStatus::GetStatus またはISSAsynchStatus::WaitForAsynchCompletion を呼び出して初期化の状態を取得できます。
さらに、SSPROP_ISSAsynchStatus プロパティが DBPROPSET_SQLSERVERROWSET プロパティ セットに追加されました。 ISSAsynchStatus インターフェイスをサポートするプロバイダーは、このプロパティを VARIANT_TRUE の値で実装する必要があります。
IDBAsynchStatus::Abort または ISSAsynchStatus::Abort を呼び出して非同期 の Initialize 呼び出しを取り消すことができます。 コンシューマーは、非同期データ ソースの初期化を明示的に要求する必要があります。 それ以外の場合、 IDBInitialize::Initialize は、データ ソース オブジェクトが完全に初期化されるまで戻りません。
注
接続プールに使用されるデータ ソース オブジェクトは、SQL Server Native Client OLE DB プロバイダーで ISSAsynchStatus インターフェイスを呼び出すことはできません。 ISSAsynchStatus インターフェイスは、プールされたデータ ソース オブジェクトには公開されません。
アプリケーションがカーソル エンジンの使用を明示的に強制する場合、 IOpenRowset::OpenRowset と IMultipleResults::GetResult は非同期処理をサポートしません。
さらに、リモート処理プロキシ/スタブ dll (MDAC 2.8) では、SQL Server Native Client の ISSAsynchStatus インターフェイスを呼び出すことができません。 ISSAsynchStatus インターフェイスは、リモート処理によって公開されません。
サービス コンポーネントは ISSAsynchStatus をサポートしていません。
実行と行セットの初期化
コマンドの実行結果を非同期的に開くよう設計されたアプリケーションでは、DBPROP_ROWSET_ASYNCH プロパティでDBPROPVAL_ASYNCH_INITIALIZE ビットを設定できます。 IDBInitialize::Initialize、ICommand::Execute、IOpenRowset::OpenRowset、IMultipleResults::GetResult を呼び出す前にこのビットを設定する場合は、riid 引数を IID_IDBAsynchStatus、IID_ISSAsynchStatus、またはIID_IUnknownに設定する必要があります。
このメソッドは、行セットの初期化が直ちに完了した場合は S_OK で直ちに返されます。また、行セットの初期化が非同期的に続行される場合はDB_S_ASYNCHRONOUSで、 ppRowset は 行セットの要求されたインターフェイスに設定されます。 SQL Server Native Client OLE DB プロバイダーの場合、このインターフェイスには IDBAsynchStatus または ISSAsynchStatus のみを指定できます。 行セットが完全に初期化されるまで、このインターフェイスは中断状態にあるかのように動作し、IID_IDBAsynchStatusまたはIID_ISSAsynchStatus以外のインターフェイスに対して QueryInterface を呼び出すと、E_NOINTERFACEが返されることがあります。 コンシューマーが非同期処理を明示的に要求しない限り、行セットは同期的に初期化されます。 要求されたすべてのインターフェイスは、 IDBAsynchStaus::GetStatus または ISSAsynchStatus::WaitForAsynchCompletion が非同期操作が完了したことを示して返されるときに使用できます。 これは必ずしも行セットが完全に設定されていることを意味するわけではありませんが、完全かつ完全に機能します。
実行されたコマンドが行セットを返さない場合でも、 IDBAsynchStatus をサポートするオブジェクトを使用して直ちに返されます。
非同期コマンド実行から複数の結果を取得する必要がある場合は、次の手順を実行する必要があります。
コマンドを実行する前に、DBPROP_ROWSET_ASYNCH プロパティのDBPROPVAL_ASYNCH_INITIALIZE ビットを設定します。
ICommand::Execute を呼び出し、IMultipleResults を要求します。
IDBAsynchStatus インターフェイスと ISSAsynchStatus インターフェイスは、QueryInterface を使用して複数の結果インターフェイスに対してクエリを実行することで取得できます。
コマンドの実行が完了すると、 IMultipleResults を通常どおり使用できます。ただし、同期ケースから 1 つの例外があります。DB_S_ASYNCHRONOUSが返される可能性があります。この場合、 IDBAsynchStatus または ISSAsynchStatus を使用して、操作が完了したタイミングを判断できます。
例示
次の例では、アプリケーションは非ブロッキング メソッドを呼び出し、その他の処理を実行した後、戻って結果を処理します。 ISSAsynchStatus::WaitForAsynchCompletion は、非同期実行操作が完了するか 、dwMilisecTimeOut で指定された時間が経過するまで、内部イベント オブジェクトを待機します。
// Set the DBPROPVAL_ASYNCH_INITIALIZE bit in the
// DBPROP_ROWSET_ASYNCH property before calling Execute().
DBPROPSET CmdPropset[1];
DBPROP CmdProperties[1];
CmdPropset[0].rgProperties = CmdProperties;
CmdPropset[0].cProperties = 1;
CmdPropset[0].guidPropertySet = DBPROPSET_ROWSET;
// Set asynch mode for command.
CmdProperties[0].dwPropertyID = DBPROP_ROWSET_ASYNCH;
CmdProperties[0].vValue.vt = VT_I4;
CmdProperties[0].vValue.lVal = DBPROPVAL_ASYNCH_INITIALIZE;
CmdProperties[0].dwOptions = DBPROPOPTIONS_REQUIRED;
hr = pICommandProps->SetProperties(1, CmdPropset);
hr = pICommand->Execute(
pUnkOuter,
IID_ISSAsynchStatus,
pParams,
pcRowsAffected,
(IUnknown**)&pISSAsynchStatus);
if (hr == DB_S_ASYNCHRONOUS)
{
// Do some work here...
hr = pISSAsynchStatus->WaitForAsynchCompletion(dwMilisecTimeOut);
if ( hr == S_OK)
{
hr = pISSAsynchStatus->QueryInterface(IID_IRowset, (void**)&pRowset);
pISSAsynchStatus->Release();
}
}
ISSAsynchStatus::WaitForAsynchCompletion は、非同期に実行する操作が完了するか 、dwMilisecTimeOut 値が渡されるまで、内部イベント オブジェクトを待機します。
次の例は、複数の結果セットを使用した非同期処理を示しています。
DBPROP CmdProperties[1];
// Set asynch mode for command.
CmdProperties[0].dwPropertyID = DBPROP_ROWSET_ASYNCH;
CmdProperties[0].vValue.vt = VT_I4;
CmdProperties[0].vValue.lVal = DBPROPVAL_ASYNCH_INITIALIZE;
hr = pICommand->Execute(
pUnkOuter,
IID_IMultipleResults,
pParams,
pcRowsAffected,
(IUnknown**)&pIMultipleResults);
// Use GetResults for ISSAsynchStatus.
hr = pIMultipleResults->GetResult(IID_ISSAsynchStatus, (void **) &pISSAsynchStatus);
if (hr == DB_S_ASYNCHRONOUS)
{
// Do some work here...
hr = pISSAsynchStatus->WaitForAsynchCompletion(dwMilisecTimeOut);
if (hr == S_OK)
{
hr = pISSAsynchStatus->QueryInterface(IID_IRowset, (void**)&pRowset);
pISSAsynchStatus->Release();
}
}
ブロックを防ぐために、次の例のように、クライアントは実行中の非同期操作の状態を確認できます。
// Set the DBPROPVAL_ASYNCH_INITIALIZE bit in the
// DBPROP_ROWSET_ASYNCH property before calling Execute().
hr = pICommand->Execute(
pUnkOuter,
IID_ISSAsynchStatus,
pParams,
pcRowsAffected,
(IUnknown**)&pISSAsynchStatus);
if (hr == DB_S_ASYNCHRONOUS)
{
do{
// Do some work...
hr = pISSAsynchStatus->GetStatus(DB_NULL_HCHAPTER, DBASYNCHOP_OPEN, NULL, NULL, &ulAsynchPhase, NULL);
}while (DBASYNCHPHASE_COMPLETE != ulAsynchPhase)
if SUCCEEDED(hr)
{
hr = pISSAsynchStatus->QueryInterface(IID_IRowset, (void**)&pRowset);
}
pIDBAsynchStatus->Release();
}
次の例は、現在実行中の非同期操作を取り消す方法を示しています。
// Set the DBPROPVAL_ASYNCH_INITIALIZE bit in the
// DBPROP_ROWSET_ASYNCH property before calling Execute().
hr = pICommand->Execute(
pUnkOuter,
IID_ISSAsynchStatus,
pParams,
pcRowsAffected,
(IUnknown**)&pISSAsynchStatus);
if (hr == DB_S_ASYNCHRONOUS)
{
// Do some work...
hr = pISSAsynchStatus->Abort(DB_NULL_HCHAPTER, DBASYNCHOP_OPEN);
}
こちらもご覧ください
SQL Server Native Client の機能
行セットのプロパティと動作
ISSAsynchStatus (OLE DB)