Ausführen asynchroner Vorgänge in SQL Server Native Client

Gilt für:SQL ServerAzure SQL-DatenbankAzure SQL Managed InstanceAzure Synapse AnalyticsAnalytics Platform System (PDW)

Wichtig

Der SQL Server Native Client (häufig abgekürzt mit SNAC) wurde aus SQL Server 2022 (16.x) und SQL Server Management Studio 19 (SSMS) entfernt. Der SQL Server Native Client (SQLNCLI oder SQLNCLI11) und der Microsoft OLE DB-Legacyanbieter für SQL Server (SQLOLEDB) werden für neue Anwendungsentwicklungen nicht empfohlen. Verwenden Sie in Zukunft den neuen Microsoft OLE DB-Treiber für SQL Server (MSOLEDBSQL) oder den neuesten Microsoft ODBC Driver for SQL Server. Informationen zu SQLNCLI, das als Komponente der SQL Server Datenbank-Engine (Versionen 2012 bis 2019) ausgeliefert wird, finden Sie in dieser Ausnahme für den Supportlebenszyklus.

SQL Server ermöglicht es Anwendungen, asynchrone Datenbankvorgänge auszuführen. Die asynchrone Verarbeitung ermöglicht es Methoden, Rückgaben unverzüglich zu übermitteln, ohne den aufrufenden Thread zu blockieren. Dadurch kann ein Großteil der Leistungsfähigkeit und Flexibilität des Multithreadings genutzt werden, ohne dass Entwickler Threads explizit erstellen oder die Synchronisation durchführen müssen. Anwendungen fordern die asynchrone Verarbeitung an, wenn sie eine Datenbankverbindung oder das Ergebnis einer Befehlsausführung initialisieren.

Öffnen und Schließen einer Datenbankverbindung

Wenn Sie den OLE DB-Anbieter von SQL Server Native Client verwenden, können Anwendungen, die zum Initialisieren eines Datenquellenobjekts entwickelt wurden, das DBPROPVAL_ASYNCH_INITIALIZE Bit in der DBPROP_INIT_ASYNCH-Eigenschaft festlegen, bevor IDBInitialize::Initialize aufgerufen wird. Wenn diese Eigenschaft festgelegt ist, antwortet der Anbieter unverzüglich auf den Aufruf von Initialize mit S_OK, wenn der Vorgang sofort ausgeführt wird, oder mit DB_S_ASYNCHRONOUS, wenn die Initialisierung asynchron fortgesetzt wird. Anwendungen können die IDBAsynchStatus- oder ISSAsynchStatus-Schnittstelle für das Datenquellenobjekt abfragen und dann IDBAsynchStatus::GetStatus oderISSAsynchStatus::WaitForAsynchCompletion aufrufen, um den Status der Initialisierung abzurufen.

Außerdem wurde dem DBPROPSET_SQLSERVERROWSET-Eigenschaftensatz die SSPROP_ISSAsynchStatus-Eigenschaft hinzugefügt. Anbieter, die die ISSAsynchStatus-Schnittstelle unterstützen, müssen diese Eigenschaft mit dem Wert VARIANT_TRUE implementieren.

IDBAsynchStatus::Abort oder ISSAsynchStatus::Abort kann aufgerufen werden, um den asynchronen Aufruf von Initialize abzubrechen. Der Consumer muss die asynchrone Datenquellinitialisierung explizit anfordern. Andernfalls erfolgt die Rückgabe durch IDBInitialize::Initialize erst, wenn das Datenquellenobjekt vollständig initialisiert wurde.

Hinweis

Datenquellenobjekte, die für verbindungspooling verwendet werden, können die ISSAsynchStatus-Schnittstelle nicht im OLE DB-Anbieter des SQL Server Native Client aufrufen. Die ISSAsynchStatus-Schnittstelle wird nicht für Datenquellenobjekte aus dem Pool verfügbar gemacht.

Wenn eine Anwendung die Verwendung der Cursor-Engine explizit erzwingt, unterstützen IOpenRowset::OpenRowset und IMultipleResults::GetResult keine asynchrone Verarbeitung.

Darüber hinaus kann die Remotingproxy-/Stub-DLL (in MDAC 2.8) die ISSAsynchStatus-Schnittstelle in SQL Server Native Client nicht aufrufen. Die ISSAsynchStatus-Schnittstelle wird durch Remoting nicht verfügbar gemacht.

Dienstkomponenten unterstützen ISSAsynchStatus nicht.

Ausführung und Rowsetinitialisierung

Anwendungen, die dafür ausgelegt sind, das Ergebnis einer Befehlsausführung asynchron zu öffnen, können das DBPROPVAL_ASYNCH_INITIALIZE-Bit in der DBPROP_ROWSET_ASYNCH-Eigenschaft festlegen. Wenn dieses Bit vor dem Aufrufen von IDBInitialize::Initialize, ICommand::Execute, IOpenRowset::OpenRowset oder IMultipleResults::GetResult festgelegt wird, muss das Argument riid auf IID_IDBAsynchStatus, IID_ISSAsynchStatus oder IID_Iunknown festgelegt werden.

Die Methode gibt unverzüglich S_OK zurück, wenn die Rowsetinitialisierung sofort ausgeführt wird, oder DB_S_ASYNCHRONOUS, wenn die Rowsetinitialisierung asynchron fortgesetzt wird, wobei ppRowset im Rowset auf die angeforderte Schnittstelle festgelegt ist. Für den OLE DB-Anbieter des nativen SQL Server-Clients kann diese Schnittstelle nur IDBAsynchStatus oder ISSAsynchStatus sein. Bis das Rowset vollständig initialisiert wurde, verhält sich diese Schnittstelle so, als befände sie sich im Zustand „Angehalten“. Der Aufruf von QueryInterface für andere Schnittstellen als IID_IDBAsynchStatus oder IID_ISSAsynchStatus führt möglicherweise zur Rückgabe von E_NOINTERFACE. Sofern der Consumer die asynchrone Verarbeitung nicht explizit anfordert, wird das Rowset synchron initialisiert. Alle angeforderten Schnittstellen sind verfügbar, wenn IDBAsynchStaus::GetStatus oder ISSAsynchStatus::WaitForAsynchCompletion die Rückgabe übermittelt, dass der asynchrone Vorgang abgeschlossen ist. Das bedeutet nicht notwendigerweise, dass das Rowset vollständig aufgefüllt ist, jedoch ist es komplett und voll funktionstüchtig.

Wenn der ausgeführte Befehl kein Rowset zurückgibt, so gibt er doch unverzüglich ein Objekt zurück, das IDBAsynchStatus unterstützt.

Wenn Sie mehrere Ergebnisse von der asynchronen Befehlsausführung benötigen, sollten Sie Folgendes tun:

  • Legen Sie das DBPROPVAL_ASYNCH_INITIALIZE-Bit der DBPROP_ROWSET_ASYNCH-Eigenschaft vor dem Ausführen des Befehls fest.

  • Rufen Sie ICommand::Execute auf, und fordern Sie IMultipleResults an.

Die IDBAsynchStatus-Schnittstelle und die ISSAsynchStatus-Schnittstelle können dann angefordert werden, indem die Schnittstelle für mehrere Ergebnisse mit QueryInterface abgefragt wird.

Wenn die Ausführung des Befehls abgeschlossen ist, kann IMultipleResults wie gewohnt verwendet werden. Es gibt jedoch eine Ausnahme für den synchronen Fall: Möglicherweise wird DB_S_ASYNCHRONOUS zurückgegeben; in diesem Fall kann mit IDBAsynchStatus oder ISSAsynchStatus ermittelt werden, wann der Vorgang abgeschlossen ist.

Beispiele

Im folgenden Beispiel ruft die Anwendung eine nicht blockierende Methode auf, führt andere Verarbeitungsvorgänge aus und kehrt dann zur Verarbeitung der Ergebnisse zurück. ISSAsynchStatus::WaitForAsynchCompletion wartet auf das interne Ereignisobjekt, bis der asynchrone Vorgang ausgeführt wurde oder die durch dwMilisecTimeOut angegebene Zeit verstrichen ist.

// 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 wartet auf das interne Ereignisobjekt, bis der asynchrone Vorgang ausgeführt oder der dwMilisecTimeOut-Wert übergeben wurde.

Im folgenden Beispiel wird die asynchrone Verarbeitung mit mehreren Resultsets veranschaulicht:

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

Der Client kann den Status eines asynchron ausgeführten Vorgangs überprüfen, um das Blockieren zu verhindern, wie im folgenden Codebeispiel gezeigt:

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

Im folgenden Beispiel wird veranschaulicht, wie Sie die gerade ausgeführte asynchrone Operation abbrechen können:

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

Weitere Informationen

SQL Server Native Client-Funktionen
Eigenschaften und Verhaltensweisen von Rowsets
ISSAsynchStatus (OLE DB)