Esecuzione di operazioni asincrone
SQL Server consente alle applicazioni di eseguire operazioni asincrone sul database. L'elaborazione asincrona consente la restituzione immediata dei metodi senza bloccare il thread chiamante. Questa caratteristica offre molto della potenza e della flessibilità del multithreading, senza richiedere allo sviluppatore la creazione esplicita di thread o la gestione della sincronizzazione. Le applicazioni richiedono l'elaborazione asincrona in caso di inizializzazione di una connessione al database o di inizializzazione del risultato dall'esecuzione di un comando.
Apertura e chiusura di una connessione al database
Quando si utilizza il provider OLE DB di SQL Server Native Client, le applicazioni progettate per inizializzare in modo asincrono un oggetto origine dati possono impostare il bit DBPROPVAL_ASYNCH_INITIALIZE nella proprietà DBPROP_INIT_ASYNCH prima di chiamare IDBInitialize::Initialize. Quando questa proprietà è impostata, il provider restituisce immediatamente dalla chiamata a Initialize S_OK, se l'operazione è stata completata immediatamente, o DB_S_ASYNCHRONOUS, se l'inizializzazione continua in modo asincrono. Le applicazioni possono eseguire query per l'interfaccia IDBAsynchStatus o ISSAsynchStatus sull'oggetto origine dati, quindi chiamano IDBAsynchStatus::GetStatus o ISSAsynchStatus::WaitForAsynchCompletion per ottenere lo stato dell'inizializzazione.
La proprietà SSPROP_ISSAsynchStatus, inoltre, è stata aggiunta al set di proprietà DBPROPSET_SQLSERVERROWSET. I provider che supportano l'interfaccia ISSAsynchStatus devono implementare questa proprietà con un valore VARIANT_TRUE.
È possibile chiamare IDBAsynchStatus::Abort o ISSAsynchStatus::Abort per annullare la chiamata a Initialize asincrona. Il consumer deve richiedere in modo esplicito l'inizializzazione asincrona dell'origine dati. In caso contrario, IDBInitialize::Initialize non restituisce nulla fino a quando l'oggetto origine dati non viene inizializzato completamente.
Nota
Gli oggetti origine dati utilizzati per pool di connessioni non possono chiamare l'interfaccia ISSAsynchStatus nel provider OLE DB di SQL Server Native Client. L'interfaccia ISSAsynchStatus non è esposta per gli oggetti di origine dati inseriti in pool.
Se un'applicazione forza in modo esplicito l'utilizzo del motore del cursore, IOpenRowset::OpenRowset e IMultipleResults::GetResult non supporteranno l'elaborazione asincrona.
Le DLL proxy/stub remote (in MDAC 2.8), inoltre, non possono chiamare l'interfaccia ISSAsynchStatus in SQL Server Native Client. L'interfaccia ISSAsynchStatus non è esposta tramite servizi remoti.
I componenti del servizio non supportano ISSAsynchStatus.
Esecuzione e inizializzazione del set di righe
Le applicazioni progettate per aprire in modo asincrono il risultato dall'esecuzione di un comando possono impostare il bit DBPROPVAL_ASYNCH_INITIALIZE nella proprietà DBPROP_ROWSET_ASYNCH. Quando questo bit viene impostato prima di chiamare IDBInitialize::Initialize, ICommand::Execute, IOpenRowset::OpenRowset o IMultipleResults::GetResult, l'argomento riid deve essere impostato su IID_IDBAsynchStatus, IID_ISSAsynchStatus o IID_IUnknown.
Il metodo restituisce immediatamente S_OK se l'inizializzazione del set di righe viene completata immediatamente oppure DB_S_ASYNCHRONOUS se il set di righe continua a essere inizializzato in modo asincrono, con ppRowset impostato sull'interfaccia richiesta nel set di righe. Per il provider OLE DB di SQL Server Native Client questa interfaccia può essere solo IDBAsynchStatus o ISSAsynchStatus. Fino a quando il set di righe non è completamente inizializzato, l'interfaccia si comporta come se fosse in stato sospeso e la chiamata a QueryInterface per le interfacce diverse da IID_IDBAsynchStatus o IID_ISSAsynchStatus può restituire E_NOINTERFACE. A meno che il consumer non richieda in modo esplicito l'elaborazione asincrona, il set di righe viene inizializzato in modo sincrono. Tutte le interfacce richieste sono disponibili quando IDBAsynchStaus::GetStatus o ISSAsynchStatus::WaitForAsynchCompletion restituisce l'indicazione che l'operazione asincrona è completa. Ciò non significa necessariamente che il set di righe è completamente popolato, ma che è completo e del tutto funzionale.
Se il comando eseguito non restituisce un set di righe, restituisce comunque immediatamente un oggetto che supporta IDBAsynchStatus.
Se è necessario ottenere più risultati dall'esecuzione di comandi asincrona, effettuare le operazioni seguenti:
Impostare il bit DBPROPVAL_ASYNCH_INITIALIZE della proprietà DBPROP_ROWSET_ASYNCH prima di eseguire il comando.
Chiamare ICommand::Executee richiedere IMultipleResults.
Le interfacce IDBAsynchStatus e ISSAsynchStatus possono quindi essere ottenute eseguendo una query sull'interfaccia con più risultati utilizzando QueryInterface.
Al termine dell'esecuzione del comando, è possibile utilizzare IMultipleResults normalmente, con un'eccezione dal caso sincrono: può essere restituito DB_S_ASYNCHRONOUS. In tal caso, è possibile utilizzare IDBAsynchStatus o ISSAsynchStatus per determinare il momento in cui l'operazione è completa.
Esempi
Nell'esempio seguente l'applicazione chiama un metodo non bloccante, esegue altre attività di elaborazione e quindi torna a elaborare i risultati. ISSAsynchStatus::WaitForAsynchCompletion resta in attesa dell'oggetto evento interno fino al completamento dell'operazione di esecuzione asincrona o allo scadere della quantità di tempo specificata da 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 resta in attesa dell'oggetto evento interno fino al completamento dell'operazione di esecuzione asincrona o al passaggio del valore dwMilisecTimeOut.
Nell'esempio seguente viene illustrata l'elaborazione asincrona con più set di risultati:
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();
}
}
Per impedire il blocco, il client può controllare lo stato di un'operazione asincrona in esecuzione, come nell'esempio seguente:
// 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();
}
Nell'esempio seguente viene illustrato come annullare l'operazione asincrona attualmente in esecuzione:
// 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);
}
Vedere anche