Esecuzione di operazioni asincrone in SQL Server Native Client

Si applica a: SQL Server database SQL di Azure Istanza gestita di SQL di Azure Azure Synapse Analytics Piattaforma di strumenti analitici (PDW)

Importante

SQL Server Native Client (SNAC) non viene fornito con:

  • SQL Server 2022 (16.x) e versioni successive
  • SQL Server Management Studio 19 e versioni successive

SQL Server Native Client (SQLNCLI o SQLNCLI11) e il provider Microsoft OLE DB legacy per SQL Server (SQLOLEDB) non sono consigliati per lo sviluppo di nuove applicazioni.

Per i nuovi progetti, usare uno dei driver seguenti:

Per SQLNCLI fornito come componente del motore di database di SQL Server (versioni dal 2012 al 2019), vedere questa Eccezione relativa al ciclo di vita del supporto.

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 usa il provider OLE DB di SQL Server Native Client, le applicazioni progettate per inizializzare un oggetto origine dati in modo asincrono possono impostare il bit di 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 nell'oggetto origine dati e quindi chiamare IDBAsynchStatus::GetStatus oISSAsynchStatus::WaitForAsynchCompletion per ottenere lo stato dell'inizializzazione.

È stata inoltre aggiunta la proprietà SSPROP_ISSAsynchStatus 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 usati per il 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'uso del motore del cursore, IOpenRowset::OpenRowset e IMultipleResults::GetResult non supporteranno l'elaborazione asincrona.

Inoltre, la dll proxy/stub remoting (in MDAC 2.8) non può chiamare l'interfaccia ISSAsynchStatus in SQL Server Native Client. L'interfaccia ISSAsynchStatus non è esposta attraverso i 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. Finché 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::Execute e richiedere IMultipleResults.

Le interfacce IDBAsynchStatus e ISSAsynchStatus possono quindi essere ottenute eseguendo una query sull'interfaccia con più risultati con QueryInterface.

Al termine dell'esecuzione del comando, è possibile usare IMultipleResults normalmente, con un'eccezione dal caso sincrono: può essere restituito DB_S_ASYNCHRONOUS. In tal caso, è possibile usare IDBAsynchStatus o ISSAsynchStatus per determinare il momento in cui l'operazione è completata.

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);  
}  

Vedi anche

Funzionalità di SQL Server Native Client
Proprietà e comportamenti dei set di righe
ISSAsynchStatus (OLE DB)