Asynchrone Ausführung (Abrufmethode)

Vor ODBC 3.8 und dem Windows 7 SDK waren asynchrone Vorgänge nur für Anweisungsfunktionen zulässig. Weitere Informationen finden Sie weiter unten in diesem Thema unter Ausführen von Anweisungsvorgängen asynchron.

ODBC 3.8 im Windows 7 SDK führte die asynchrone Ausführung bei verbindungsbezogenen Vorgängen ein. Weitere Informationen finden Sie weiter unten in diesem Thema im Abschnitt Ausführen von Verbindungsvorgängen asynchron .

Im Windows 7 SDK hat eine Anwendung für asynchrone Anweisungs- oder Verbindungsvorgänge mithilfe der Abfragemethode ermittelt, dass der asynchrone Vorgang abgeschlossen war. Ab dem Windows 8 SDK können Sie mithilfe der Benachrichtigungsmethode feststellen, dass ein asynchroner Vorgang abgeschlossen ist. Weitere Informationen finden Sie unter Asynchrone Ausführung (Benachrichtigungsmethode).

Standardmäßig führen Treiber ODBC-Funktionen synchron aus. Das heißt, die Anwendung ruft eine Funktion auf, und der Treiber gibt die Steuerung an die Anwendung erst zurück, wenn die Ausführung der Funktion abgeschlossen ist. Einige Funktionen können jedoch asynchron ausgeführt werden. Das heißt, die Anwendung ruft die Funktion auf, und der Treiber gibt nach minimaler Verarbeitung die Steuerung an die Anwendung zurück. Die Anwendung kann dann andere Funktionen aufrufen, während die erste Funktion noch ausgeführt wird.

Die asynchrone Ausführung wird für die meisten Funktionen unterstützt, die größtenteils in der Datenquelle ausgeführt werden, z. B. für die Funktionen zum Herstellen von Verbindungen, Vorbereiten und Ausführen von SQL-Anweisungen, Abrufen von Metadaten, Abrufen von Daten und Commit von Transaktionen. Es ist am nützlichsten, wenn die Aufgabe, die für die Datenquelle ausgeführt wird, lange dauert, z. B. ein Anmeldeprozess oder eine komplexe Abfrage für eine große Datenbank.

Wenn die Anwendung eine Funktion mit einer Anweisung oder Verbindung ausführt, die für die asynchrone Verarbeitung aktiviert ist, führt der Treiber eine minimale Verarbeitungsmenge aus (z. B. das Überprüfen von Argumenten auf Fehler), übergibt die Verarbeitung an die Datenquelle und gibt die Steuerung an die Anwendung mit dem SQL_STILL_EXECUTING Rückgabecode zurück. Die Anwendung führt dann andere Aufgaben aus. Um zu bestimmen, wann die asynchrone Funktion abgeschlossen ist, ruft die Anwendung den Treiber in regelmäßigen Abständen ab, indem sie die Funktion mit denselben Argumenten aufruft, die sie ursprünglich verwendet hat. Wenn die Funktion noch ausgeführt wird, gibt sie SQL_STILL_EXECUTING zurück. Wenn die Ausführung abgeschlossen ist, wird der Code zurückgegeben, der bei synchroner Ausführung zurückgegeben worden wäre, z. B. SQL_SUCCESS, SQL_ERROR oder SQL_NEED_DATA.

Ob eine Funktion synchron oder asynchron ausgeführt wird, ist treiberspezifisch. Angenommen, die Resultsetmetadaten werden im Treiber zwischengespeichert. In diesem Fall dauert die Ausführung von SQLDescribeCol sehr wenig, und der Treiber sollte die Funktion einfach ausführen, anstatt die Ausführung künstlich zu verzögern. Wenn der Treiber hingegen die Metadaten aus der Datenquelle abrufen muss, sollte er die Steuerung an die Anwendung zurückgeben, während er dies ausführt. Daher muss die Anwendung in der Lage sein, einen anderen Rückgabecode als SQL_STILL_EXECUTING zu verarbeiten, wenn sie eine Funktion zum ersten Mal asynchron ausführt.

Asynchrones Ausführen von Anweisungsvorgängen

Die folgenden Anweisungsfunktionen werden für eine Datenquelle ausgeführt und können asynchron ausgeführt werden:

Die asynchrone Anweisungsausführung wird abhängig von der Datenquelle entweder auf Anweisungs- oder Verbindungsbasis gesteuert. Das heißt, die Anwendung gibt nicht an, dass eine bestimmte Funktion asynchron ausgeführt werden soll, sondern dass jede für eine bestimmte Anweisung ausgeführte Funktion asynchron ausgeführt werden soll. Um herauszufinden, welche Anwendung unterstützt wird, ruft eine Anwendung SQLGetInfo mit der Option SQL_ASYNC_MODE auf. SQL_AM_CONNECTION wird zurückgegeben, wenn die asynchrone Ausführung auf Verbindungsebene (für ein Anweisungshandle) unterstützt wird; SQL_AM_STATEMENT, wenn die asynchrone Ausführung auf Anweisungsebene unterstützt wird.

Um anzugeben, dass mit einer bestimmten Anweisung ausgeführte Funktionen asynchron ausgeführt werden sollen, ruft die Anwendung SQLSetStmtAttr mit dem attribut SQL_ATTR_ASYNC_ENABLE auf und legt es auf SQL_ASYNC_ENABLE_ON fest. Wenn die asynchrone Verarbeitung auf Verbindungsebene unterstützt wird, ist das SQL_ATTR_ASYNC_ENABLE-Anweisungsattribut schreibgeschützt, und sein Wert ist mit dem Verbindungsattribute der Verbindung identisch, für die die Anweisung zugewiesen wurde. Es ist treiberspezifisch, ob der Wert des Anweisungsattributs zur Anweisungszuordnungszeit oder höher festgelegt wird. Beim Festlegen wird SQL_ERROR und SQLSTATE HYC00 zurückgegeben (optionales Feature nicht implementiert).

Um anzugeben, dass mit einer bestimmten Verbindung ausgeführte Funktionen asynchron ausgeführt werden sollen, ruft die Anwendung SQLSetConnectAttr mit dem attribut SQL_ATTR_ASYNC_ENABLE auf und legt es auf SQL_ASYNC_ENABLE_ON fest. Alle zukünftigen Anweisungshandles, die für die Verbindung zugeordnet sind, werden für die asynchrone Ausführung aktiviert. Es ist treiberdefiniert, ob vorhandene Anweisungshandles durch diese Aktion aktiviert werden. Wenn SQL_ATTR_ASYNC_ENABLE auf SQL_ASYNC_ENABLE_OFF festgelegt ist, befinden sich alle Anweisungen für die Verbindung im synchronen Modus. Ein Fehler wird zurückgegeben, wenn die asynchrone Ausführung aktiviert ist, während eine aktive Anweisung für die Verbindung vorhanden ist.

Um die maximale Anzahl aktiver gleichzeitiger Anweisungen im asynchronen Modus zu ermitteln, die der Treiber für eine bestimmte Verbindung unterstützen kann, ruft die Anwendung SQLGetInfo mit der Option SQL_MAX_ASYNC_CONCURRENT_STATEMENTS auf.

Der folgende Code veranschaulicht die Funktionsweise des Abfragemodells:

SQLHSTMT  hstmt1;  
SQLRETURN rc;  
  
// Specify that the statement is to be executed asynchronously.  
SQLSetStmtAttr(hstmt1, SQL_ATTR_ASYNC_ENABLE, SQL_ASYNC_ENABLE_ON, 0);  
  
// Execute a SELECT statement asynchronously.  
while ((rc=SQLExecDirect(hstmt1,"SELECT * FROM Orders",SQL_NTS))==SQL_STILL_EXECUTING) {  
   // While the statement is still executing, do something else.  
   // Do not use hstmt1, because it is being used asynchronously.  
}  
  
// When the statement has finished executing, retrieve the results.  

Während eine Funktion asynchron ausgeführt wird, kann die Anwendung Funktionen für alle anderen Anweisungen aufrufen. Die Anwendung kann auch Funktionen für jede Verbindung aufrufen, mit Ausnahme der Verbindung, die der asynchronen Anweisung zugeordnet ist. Die Anwendung kann jedoch nur die ursprüngliche Funktion und die folgenden Funktionen (mit dem Anweisungshandle oder der zugehörigen Verbindung, umgebungshandle) aufrufen, nachdem ein Anweisungsvorgang SQL_STILL_EXECUTING zurückgibt:

Wenn die Anwendung eine andere Funktion mit der asynchronen Anweisung oder mit der Verbindung aufruft, die dieser Anweisung zugeordnet ist, gibt die Funktion z. B. SQLSTATE HY010 (Funktionssequenzfehler) zurück.

SQLHDBC       hdbc1, hdbc2;  
SQLHSTMT      hstmt1, hstmt2, hstmt3;  
SQLCHAR *     SQLStatement = "SELECT * FROM Orders";  
SQLUINTEGER   InfoValue;  
SQLRETURN     rc;  
  
SQLAllocHandle(SQL_HANDLE_STMT, hdbc1, &hstmt1);  
SQLAllocHandle(SQL_HANDLE_STMT, hdbc1, &hstmt2);  
SQLAllocHandle(SQL_HANDLE_STMT, hdbc2, &hstmt3);  
  
// Specify that hstmt1 is to be executed asynchronously.  
SQLSetStmtAttr(hstmt1, SQL_ATTR_ASYNC_ENABLE, SQL_ASYNC_ENABLE_ON, 0);  
  
// Execute hstmt1 asynchronously.  
while ((rc = SQLExecDirect(hstmt1, SQLStatement, SQL_NTS)) == SQL_STILL_EXECUTING) {  
   // The following calls return HY010 because the previous call to  
   // SQLExecDirect is still executing asynchronously on hstmt1. The  
   // first call uses hstmt1 and the second call uses hdbc1, on which  
   // hstmt1 is allocated.  
   SQLExecDirect(hstmt1, SQLStatement, SQL_NTS);   // Error!  
   SQLGetInfo(hdbc1, SQL_UNION, (SQLPOINTER) &InfoValue, 0, NULL);   // Error!  
  
   // The following calls do not return errors. They use a statement  
   // handle other than hstmt1 or a connection handle other than hdbc1.  
   SQLExecDirect(hstmt2, SQLStatement, SQL_NTS);   // OK  
   SQLTables(hstmt3, NULL, 0, NULL, 0, NULL, 0, NULL, 0);   // OK  
   SQLGetInfo(hdbc2, SQL_UNION, (SQLPOINTER) &InfoValue, 0, NULL);   // OK  
}  

Wenn eine Anwendung eine Funktion aufruft, um zu bestimmen, ob sie weiterhin asynchron ausgeführt wird, muss sie das ursprüngliche Anweisungshandle verwenden. Dies liegt daran, dass die asynchrone Ausführung auf Anweisungsbasis nachverfolgt wird. Die Anwendung muss auch gültige Werte für die anderen Argumente bereitstellen - die ursprünglichen Argumente tun dies -, um die Fehlerüberprüfung in der Vergangenheit im Treiber-Manager zu erhalten. Nachdem der Treiber jedoch das Anweisungshandle überprüft und feststellt, dass die Anweisung asynchron ausgeführt wird, ignoriert er alle anderen Argumente.

Während eine Funktion asynchron ausgeführt wird , d. h. nachdem sie SQL_STILL_EXECUTING zurückgegeben hat und bevor sie einen anderen Code zurückgibt, kann die Anwendung sie abbrechen, indem SIE SQLCancel oder SQLCancelHandle mit demselben Anweisungshandle aufruft. Dadurch wird nicht garantiert, dass die Funktionsausführung abgebrochen wird. Beispielsweise kann die Funktion bereits abgeschlossen sein. Darüber hinaus gibt der von SQLCancel oder SQLCancelHandle zurückgegebene Code nur an, ob der Versuch, die Funktion abzubrechen, erfolgreich war, und nicht, ob die Funktion tatsächlich abgebrochen wurde. Um festzustellen, ob die Funktion abgebrochen wurde, ruft die Anwendung die Funktion erneut auf. Wenn die Funktion abgebrochen wurde, gibt sie SQL_ERROR und SQLSTATE HY008 (Vorgang abgebrochen) zurück. Wenn die Funktion nicht abgebrochen wurde, gibt sie einen anderen Code zurück, z. B. SQL_SUCCESS, SQL_STILL_EXECUTING oder SQL_ERROR mit einem anderen SQLSTATE.

Um die asynchrone Ausführung einer bestimmten Anweisung zu deaktivieren, wenn der Treiber die asynchrone Verarbeitung auf Anweisungsebene unterstützt, ruft die Anwendung SQLSetStmtAttr mit dem attribut SQL_ATTR_ASYNC_ENABLE auf und legt es auf SQL_ASYNC_ENABLE_OFF fest. Wenn der Treiber die asynchrone Verarbeitung auf Verbindungsebene unterstützt, ruft die Anwendung SQLSetConnectAttr auf, um SQL_ATTR_ASYNC_ENABLE auf SQL_ASYNC_ENABLE_OFF festzulegen, wodurch die asynchrone Ausführung aller Anweisungen für die Verbindung deaktiviert wird.

Die Anwendung sollte Diagnosedatensätze in der wiederholten Schleife der ursprünglichen Funktion verarbeiten. Wenn SQLGetDiagField oder SQLGetDiagRec aufgerufen wird, wenn eine asynchrone Funktion ausgeführt wird, wird die aktuelle Liste der Diagnosedatensätze zurückgegeben. Bei jeder Wiederholung des ursprünglichen Funktionsaufrufs werden frühere Diagnosedatensätze gelöscht.

Asynchrones Ausführen von Verbindungsvorgängen

Vor ODBC 3.8 war die asynchrone Ausführung für anweisungsbezogene Vorgänge wie Vorbereiten, Ausführen und Abrufen sowie für Katalogmetadatenvorgänge zulässig. Ab ODBC 3.8 ist die asynchrone Ausführung auch für verbindungsbezogene Vorgänge wie Verbinden, Trennen, Commit und Rollback möglich.

Weitere Informationen zu ODBC 3.8 finden Sie unter Neuerungen in ODBC 3.8.

Das asynchrone Ausführen von Verbindungsvorgängen ist in den folgenden Szenarien nützlich:

  • Wenn eine kleine Anzahl von Threads eine große Anzahl von Geräten mit sehr hohen Datenraten verwaltet. Um die Reaktionsfähigkeit und Skalierbarkeit zu maximieren, ist es wünschenswert, dass alle Vorgänge asynchron sind.

  • Wenn Sie Datenbankvorgänge über mehrere Verbindungen überlappen möchten, um verstrichene Übertragungszeiten zu verkürzen.

  • Effiziente asynchrone ODBC-Aufrufe und die Möglichkeit, Verbindungsvorgänge abzubrechen, ermöglichen es einer Anwendung, dem Benutzer zu ermöglichen, jeden langsamen Vorgang abzubrechen, ohne auf Timeouts warten zu müssen.

Die folgenden Funktionen, die für Verbindungshandles ausgeführt werden, können jetzt asynchron ausgeführt werden:

Um zu ermitteln, ob ein Treiber asynchrone Vorgänge für diese Funktionen unterstützt, ruft eine Anwendung SQLGetInfo mit SQL_ASYNC_DBC_FUNCTIONS auf. SQL_ASYNC_DBC_CAPABLE wird zurückgegeben, wenn asynchrone Vorgänge unterstützt werden. SQL_ASYNC_DBC_NOT_CAPABLE wird zurückgegeben, wenn asynchrone Vorgänge nicht unterstützt werden.

Um anzugeben, dass mit einer bestimmten Verbindung ausgeführte Funktionen asynchron ausgeführt werden sollen, ruft die Anwendung SQLSetConnectAttr auf und legt das attribut SQL_ATTR_ASYNC_DBC_FUNCTIONS_ENABLE auf SQL_ASYNC_DBC_ENABLE_ON fest. Das Festlegen eines Verbindungsattributes vor dem Herstellen einer Verbindung wird immer synchron ausgeführt. Außerdem wird der Vorgang, der das Verbindungsattribut SQL_ATTR_ASYNC_DBC_FUNCTIONS_ENABLE mit SQLSetConnectAttr festlegt, immer synchron ausgeführt.

Eine Anwendung kann den asynchronen Vorgang aktivieren, bevor sie eine Verbindung herstellt. Da der Treiber-Manager vor dem Herstellen einer Verbindung nicht ermitteln kann, welcher Treiber verwendet werden soll, gibt der Treiber-Manager in SQLSetConnectAttr immer erfolgreich zurück. Es kann jedoch möglicherweise keine Verbindung hergestellt werden, wenn der ODBC-Treiber keine asynchronen Vorgänge unterstützt.

Im Allgemeinen kann es höchstens eine asynchron ausführende Funktion geben, die einem bestimmten Verbindungshandle oder Anweisungshandle zugeordnet ist. Ein Verbindungshandle kann jedoch mehr als ein zugeordnetes Anweisungshandle aufweisen. Wenn kein asynchroner Vorgang für das Verbindungshandle ausgeführt wird, kann ein zugeordnetes Anweisungshandle einen asynchronen Vorgang ausführen. Ebenso können Sie einen asynchronen Vorgang für ein Verbindungshandle ausführen, wenn für ein zugeordnetes Anweisungshandle keine asynchronen Vorgänge ausgeführt werden. Ein Versuch, einen asynchronen Vorgang mit einem Handle auszuführen, das derzeit einen asynchronen Vorgang ausführt, gibt HY010 als "Funktionssequenzfehler" zurück.

Wenn ein Verbindungsvorgang SQL_STILL_EXECUTING zurückgibt, kann eine Anwendung nur die ursprüngliche Funktion und die folgenden Funktionen für dieses Verbindungshandle aufrufen:

  • SQLCancelHandle (auf dem Verbindungshandle)

  • SQLGetDiagField

  • SQLGetDiagRec

  • SQLAllocHandle (Zuweisung von ENV/DBC)

  • SQLAllocHandleStd (Zuweisung von ENV/DBC)

  • SQLGetEnvAttr

  • SQLGetConnectAttr

  • SQLDataSources

  • SQLDrivers

  • SQLGetInfo

  • SQLGetFunctions

Die Anwendung sollte Diagnosedatensätze in der wiederholten Schleife der ursprünglichen Funktion verarbeiten. Wenn SQLGetDiagField oder SQLGetDiagRec aufgerufen wird, wenn eine asynchrone Funktion ausgeführt wird, wird die aktuelle Liste der Diagnosedatensätze zurückgegeben. Bei jeder Wiederholung des ursprünglichen Funktionsaufrufs werden frühere Diagnosedatensätze gelöscht.

Wenn eine Verbindung asynchron geöffnet oder geschlossen wird, ist der Vorgang abgeschlossen, wenn die Anwendung SQL_SUCCESS oder SQL_SUCCESS_WITH_INFO im ursprünglichen Funktionsaufruf empfängt.

ODBC 3.8, SQLCancelHandle, wurde eine neue Funktion hinzugefügt. Diese Funktion bricht die sechs Verbindungsfunktionen ab (SQLBrowseConnect, SQLConnect, SQLDisconnect, SQLDriverConnect, SQLEndTran und SQLSetConnectAttr). Eine Anwendung sollte SQLGetFunctions aufrufen, um festzustellen, ob der Treiber SQLCancelHandle unterstützt. Wie bei SQLCancel bedeutet dies nicht, dass der Vorgang abgebrochen wurde, wenn SQLCancelHandle den Erfolg zurückgibt. Eine Anwendung sollte die ursprüngliche Funktion erneut aufrufen, um festzustellen, ob der Vorgang abgebrochen wurde. MIT SQLCancelHandle können Sie asynchrone Vorgänge für Verbindungshandles oder Anweisungshandles abbrechen. Die Verwendung von SQLCancelHandle zum Abbrechen eines Vorgangs für ein Anweisungshandle ist identisch mit dem Aufrufen von SQLCancel.

Es ist nicht erforderlich, sqlCancelHandle und asynchrone Verbindungsvorgänge gleichzeitig zu unterstützen. Ein Treiber kann asynchrone Verbindungsvorgänge unterstützen, aber nicht SQLCancelHandle oder umgekehrt.

Asynchrone Verbindungsvorgänge und SQLCancelHandle können auch von ODBC 3.x- und ODBC 2.x-Anwendungen mit einem ODBC 3.8-Treiber und ODBC 3.8-Treiber-Manager verwendet werden. Informationen dazu, wie Sie einer älteren Anwendung die Verwendung neuer Features in einer späteren ODBC-Version ermöglichen, finden Sie unter Kompatibilitätsmatrix.

Verbindungspooling

Wenn das Verbindungspooling aktiviert ist, werden asynchrone Vorgänge zum Herstellen einer Verbindung (mit SQLConnect und SQLDriverConnect) und zum Schließen einer Verbindung mit SQLDisconnect nur minimal unterstützt. Eine Anwendung sollte jedoch weiterhin in der Lage sein, den SQL_STILL_EXECUTING Rückgabewert von SQLConnect, SQLDriverConnect und SQLDisconnect zu verarbeiten.

Wenn das Verbindungspooling aktiviert ist, werden SQLEndTran und SQLSetConnectAttr für asynchrone Vorgänge unterstützt.

Beispiele

A. Aktivieren der asynchronen Ausführung von Verbindungsfunktionen

Das folgende Beispiel zeigt, wie Sie SQLSetConnectAttr verwenden, um die asynchrone Ausführung für verbindungsbezogene Funktionen zu aktivieren.

BOOL AsyncConnect (SQLHANDLE hdbc)   
{  
   SQLRETURN r;  
   SQLHANDLE hdbc;  
  
   // Enable asynchronous execution of connection functions.  
   // This must be executed synchronously, that is r != SQL_STILL_EXECUTING  
   r = SQLSetConnectAttr(  
         hdbc,   
         SQL_ATTR_ASYNC_DBC_FUNCTIONS_ENABLE,  
         reinterpret_cast<SQLPOINTER> (SQL_ASYNC_DBC_ENABLE_ON),  
         0);  
   if (r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO)   
   {  
      return FALSE;  
   }  
  
   TCHAR szConnStrIn[256] = _T("DSN=AsyncDemo");  
  
   r = SQLDriverConnect(hdbc, NULL, (SQLTCHAR *) szConnStrIn, SQL_NTS, NULL, 0, NULL, SQL_DRIVER_NOPROMPT);  
  
   if (r == SQL_ERROR)   
   {  
      // Use SQLGetDiagRec to process the error.  
      // If SQLState is HY114, the driver does not support asynchronous execution.  
      return FALSE;  
   }  
  
   while (r == SQL_STILL_EXECUTING)   
   {  
      // Do something else.  
  
      // Check for completion, with the same set of arguments.  
      r = SQLDriverConnect(hdbc, NULL, (SQLTCHAR *) szConnStrIn, SQL_NTS, NULL, 0, NULL, SQL_DRIVER_NOPROMPT);  
   }  
  
   if (r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO)   
   {  
      return FALSE;  
   }  
  
   return TRUE;  
}  
  

B. Asynchrone Commitvorgänge

Dieses Beispiel zeigt asynchrone Commitvorgänge. Rollbackvorgänge können auch auf diese Weise durchgeführt werden.

BOOL AsyncCommit ()   
{  
   SQLRETURN r;   
  
   // Assume that SQL_ATTR_ASYNC_DBC_FUNCTIONS_ENABLE is SQL_ASYNC_DBC_ENABLE_ON.  
  
   r = SQLEndTran(SQL_HANDLE_DBC, hdbc, SQL_COMMIT);  
   while (r == SQL_STILL_EXECUTING)   
   {  
      // Do something else.  
  
      // Check for completion with the same set of arguments.  
      r = SQLEndTran(SQL_HANDLE_DBC, hdbc, SQL_COMMIT);  
   }  
  
   if (r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO)   
   {  
      return FALSE;  
   }  
   return TRUE;  
}  

Weitere Informationen

Ausführen von ODBC-Anweisungen