Freigeben über


Ausführen asynchroner Vorgänge

SQL Server ermöglicht Anwendungen das Ausführen asynchroner Datenbankvorgänge. Mit der asynchronen Verarbeitung können Methoden sofort zurückgegeben werden, ohne den aufrufenden Thread zu blockieren. Dies ermöglicht einen Großteil der Leistungsfähigkeit und Flexibilität von Multithreading, ohne dass der Entwickler explizit Threads erstellen oder die Synchronisierung behandeln muss. Anwendungen fordern eine asynchrone Verarbeitung beim Initialisieren einer Datenbankverbindung oder beim Initialisieren des Ergebnisses aus der Ausführung eines Befehls an.

Öffnen und Schließen einer Datenbankverbindung

Bei Verwendung des OLE DB-Anbieters von SQL Server Native Client 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 wird, gibt der Anbieter sofort vom Aufruf an Initialize mit S_OK zurück, wenn der Vorgang sofort abgeschlossen wurde, oder DB_S_ASYNCHRONOUS, wenn die Initialisierung asynchron fortgesetzt wird. Anwendungen können die IDBAsynchStatus - oder ISSAsynchStatus-Schnittstellefür das Datenquellenobjekt abfragen und dann IDBAsynchStatus::GetStatus oderISSAsynchStatus::WaitForAsynchCompletion aufrufen, um den Status der Initialisierung abzurufen.

Darüber hinaus wurde die SSPROP_ISSAsynchStatus-Eigenschaft dem DBPROPSET_SQLSERVERROWSET-Eigenschaftensatz 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 Initialize-Aufruf abzubrechen. Der Consumer muss explizit eine asynchrone Datenquelleninitialisierung anfordern. Andernfalls wird IDBInitialize::Initialize erst zurückgegeben, wenn das Datenquellenobjekt vollständig initialisiert ist.

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 für zusammengefasste Datenquellenobjekte nicht verfügbar gemacht.

Wenn eine Anwendung die Verwendung des Cursormoduls explizit erzwingt, unterstützt 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 nicht über Remoting verfügbar gemacht.

Dienstkomponenten unterstützen ISSAsynchStatus nicht.

Initialisierung von Ausführung und Rowset

Anwendungen, die zum asynchronen Öffnen des Ergebnisses aus der Ausführung eines Befehls entwickelt wurden, können das DBPROPVAL_ASYNCH_INITIALIZE Bit in der eigenschaft DBPROP_ROWSET_ASYNCH festlegen. Wenn Sie dieses Bit vor dem Aufrufen von IDBInitialize::Initialize, ICommand::Execute, IOpenRowset::OpenRowset oder IMultipleResults::GetResult festlegen, muss das Riid-Argument auf IID_IDBAsynchStatus, IID_ISSAsynchStatus oder IID_IUnknown festgelegt werden.

Die Methode wird sofort mit S_OK zurückgegeben, wenn die Rowsetinitialisierung sofort abgeschlossen ist, oder mit DB_S_ASYNCHRONOUS, wenn das Rowset asynchron initialisiert wird, wobei ppRowset auf die angeforderte Schnittstelle im Rowset 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 ist, verhält sich diese Schnittstelle so, als wäre sie in einem angehaltenen Zustand, und das Aufrufen von QueryInterface für andere Schnittstellen als IID_IDBAsynchStatus oder IID_ISSAsynchStatus kann E_NOINTERFACE zurückgeben. Sofern der Consumer nicht explizit eine asynchrone Verarbeitung anfordert, wird das Rowset synchron initialisiert. Alle angeforderten Schnittstellen sind verfügbar, wenn IDBAsynchStaus::GetStatus oder ISSAsynchStatus::WaitForAsynchCompletion mit dem Hinweis zurückgibt, dass der asynchrone Vorgang abgeschlossen ist. Dies bedeutet nicht unbedingt, dass das Rowset vollständig ausgefüllt ist, aber vollständig und voll funktionsfähig ist.

Wenn der ausgeführte Befehl kein Rowset zurückgibt, wird es immer noch sofort mit einem Objekt zurückgegeben, das IDBAsynchStatus unterstützt.

Wenn Sie mehrere Ergebnisse aus der asynchronen Befehlsausführung erhalten müssen, sollten Sie:

  • Legen Sie die DBPROPVAL_ASYNCH_INITIALIZE Bit der DBPROP_ROWSET_ASYNCH-Eigenschaft fest, bevor Sie den Befehl ausführen.

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

Die SCHNITTSTELLEN IDBAsynchStatus und ISSAsynchStatus können dann durch Abfragen der multiplen Ergebnisschnittstelle mithilfe von QueryInterface abgerufen werden.

Wenn der Befehl die Ausführung abgeschlossen hat, kann IMultipleResults normal verwendet werden, mit einer Ausnahme vom synchronen Fall: DB_S_ASYNCHRONOUS kann zurückgegeben werden, in diesem Fall kann IDBAsynchStatus oder ISSAsynchStatus verwendet werden, um zu bestimmen, wann der Vorgang abgeschlossen ist.

Beispiele

Im folgenden Beispiel ruft die Anwendung eine nicht blockierende Methode auf, führt eine andere Verarbeitung durch und gibt dann zurück, um die Ergebnisse zu verarbeiten. ISSAsynchStatus::WaitForAsynchCompletion wartet auf das interne Ereignisobjekt, bis der asynchron ausgeführte Vorgang abgeschlossen ist oder die durch dwMilisecTimeOut angegebene Zeit übergeben wird.

// 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 asynchron ausgeführte Vorgang abgeschlossen ist oder der dwMilisecTimeOut-Wert übergeben wird.

Das folgende Beispiel zeigt eine asynchrone Verarbeitung mit mehreren Resultsets:

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

Um das Blockieren zu verhindern, kann der Client den Status eines ausgeführten asynchronen Vorgangs überprüfen, wie im folgenden Beispiel 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 den aktuell ausgeführten asynchronen Vorgang 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);  
}  

Siehe auch

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