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 unter " Ausführen von Anweisungsvorgängen asynchron" weiter unten in diesem Thema.
ODBC 3.8 im Windows 7 SDK führte die asynchrone Ausführung für verbindungsbezogene Vorgänge ein. Weitere Informationen finden Sie im Abschnitt "Ausführen von Verbinden ionvorgängen asynchron" weiter unten in diesem Thema.
Im Windows 7 SDK hat eine Anwendung für asynchrone Anweisungen oder Verbindungsvorgänge festgestellt, dass der asynchrone Vorgang mit der Abrufmethode abgeschlossen wurde. Ab dem Windows 8 SDK können Sie mithilfe der Benachrichtigungsmethode ermitteln, dass ein asynchroner Vorgang abgeschlossen ist. Weitere Informationen finden Sie unter Asynchrone Ausführung (Notification-Methode).For more information, see Asynchronous Execution (Notification Method).
Standardmäßig führen Treiber ODBC-Funktionen synchron aus. d. h. die Anwendung ruft eine Funktion auf, und der Treiber gibt erst die Steuerung an die Anwendung zurück, wenn sie die Ausführung der Funktion abgeschlossen hat. Einige Funktionen können jedoch asynchron ausgeführt werden. d. h., 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 weitgehend auf der Datenquelle ausgeführt werden, z. B. die Funktionen zum Herstellen von Verbindungen, vorbereiten und ausführen von SQL-Anweisungen, Abrufen von Metadaten, Abrufen von Daten und Commit-Transaktionen. Es ist am nützlichsten, wenn die Aufgabe, die in der Datenquelle ausgeführt wird, sehr lange dauert, z. B. einen Anmeldevorgang 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. Überprüfen von Argumenten auf Fehler), die Verarbeitung der Hände an die Datenquelle und gibt die Steuerung mit dem SQL_STILL_EXECUTING Rückgabecode an die Anwendung zurück. Die Anwendung führt dann andere Aufgaben aus. Um festzustellen, wann die asynchrone Funktion abgeschlossen ist, ruft die Anwendung den Treiber in regelmäßigen Intervallen ab, indem die Funktion mit denselben Argumenten aufgerufen wird, die ursprünglich verwendet wurden. Wenn die Funktion weiterhin ausgeführt wird, wird SQL_STILL_EXECUTING zurückgegeben. Wenn sie die Ausführung abgeschlossen hat, wird der zurückgegebene Code zurückgegeben, wenn er synchron ausgeführt wurde, z. B. SQL_SUCCESS, SQL_ERROR oder SQL_NEED_DATA.
Gibt an, ob eine Funktion synchron oder asynchron ausgeführt wird, treiberspezifisch ist. Angenommen, die Resultsetmetadaten werden im Treiber zwischengespeichert. In diesem Fall dauert es sehr wenig Zeit, SQLDescribeCol auszuführen, und der Treiber sollte die Funktion einfach ausführen, anstatt die Ausführung künstlich zu verzögern. Wenn der Treiber jedoch die Metadaten aus der Datenquelle abrufen muss, sollte die Steuerung an die Anwendung zurückgegeben werden, während er dies tut. Daher muss die Anwendung in der Lage sein, einen anderen Rückgabecode als SQL_STILL_EXECUTING zu behandeln, wenn sie eine Funktion asynchron ausführt.
Asynchrones Ausführen von Anweisungsvorgängen
Die folgenden Anweisungsfunktionen funktionieren auf einer Datenquelle und können asynchron ausgeführt werden:
SQLBulkOperations
SQLColAttribute
SQLColumnPrivileges
SQLColumns
SQLDescribeCol
SQLDescribeParam
SQLExecDirect
SQLExecute
SQLFetch
Die asynchrone Anweisungsausführung wird je nach Datenquelle entweder pro Anweisung oder pro Verbindung gesteuert. Das heißt, die Anwendung gibt nicht an, dass eine bestimmte Funktion asynchron ausgeführt werden soll, sondern dass jede funktion, die für eine bestimmte Anweisung ausgeführt wird, asynchron ausgeführt werden soll. Um herauszufinden, welche unterstützt wird, ruft eine Anwendung SQLGetInfo mit einer Option von 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 funktionen, die mit einer bestimmten Anweisung ausgeführt werden, asynchron ausgeführt werden sollen, ruft die Anwendung SQLSetStmtAttr mit dem SQL_ATTR_ASYNC_ENABLE-Attribut auf und legt sie auf SQL_ASYNC_ENABLE_ON fest. Wenn die asynchrone Verarbeitung auf Verbindungsebene unterstützt wird, ist das attribut der SQL_ATTR_ASYNC_ENABLE-Anweisung schreibgeschützt und sein Wert entspricht dem Verbindungsattribute der Verbindung, der die Anweisung zugewiesen wurde. Es ist treiberspezifisch, ob der Wert des Anweisungsattributs zur Zeit der Anweisungszuweisung oder höher festgelegt wird. Wenn Sie versuchen, es festzulegen, wird SQL_ERROR und SQLSTATE HYC00 (Optionales Feature nicht implementiert) zurückgegeben.
Um anzugeben, dass funktionen, die mit einer bestimmten Verbindung ausgeführt werden, asynchron ausgeführt werden sollen, ruft die Anwendung SQLSet Verbinden Attr mit dem attribut SQL_ATTR_ASYNC_ENABLE auf und legt sie auf SQL_ASYNC_ENABLE_ON fest. Alle zukünftigen Anweisungshandles, die der 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, wie das Abfragemodell funktioniert:
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 des einer asynchronen Anweisung zugeordneten. Die Anwendung kann jedoch nur die ursprüngliche Funktion und die folgenden Funktionen aufrufen (mit dem Anweisungshandle oder der zugehörigen Verbindung, Umgebungshandle), 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 festzustellen, ob sie weiterhin asynchron ausgeführt wird, muss sie das ursprüngliche Anweisungshandle verwenden. Dies liegt daran, dass die asynchrone Ausführung pro Anweisung nachverfolgt wird. Die Anwendung muss auch gültige Werte für die anderen Argumente angeben – die ursprünglichen Argumente werden ausgeführt – um die Fehlerüberprüfung im Treiber-Manager zu erhalten. Nachdem der Treiber das Anweisungshandle überprüft und bestimmt, dass die Anweisung asynchron ausgeführt wird, ignoriert er jedoch 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. Dies ist nicht garantiert, um die Funktionsausführung abzubrechen. Die Funktion kann beispielsweise 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, 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, wird SQL_ERROR und SQLSTATE HY008 (Vorgang abgebrochen) zurückgegeben. Wenn die Funktion nicht abgebrochen wurde, wird ein anderer Code wie SQL_SUCCESS, SQL_STILL_EXECUTING oder SQL_ERROR mit einem anderen SQLSTATE zurückgegeben.
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 sie auf SQL_ASYNC_ENABLE_OFF fest. Wenn der Treiber die asynchrone Verarbeitung auf Verbindungsebene unterstützt, ruft die Anwendung SQLSet Verbinden Attr 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, gibt sie die aktuelle Liste der Diagnosedatensätze zurück. Jedes Mal, wenn der ursprüngliche Funktionsaufruf wiederholt wird, werden vorherige Diagnosedatensätze gelöscht.
Asynchrones Ausführen von Verbinden ion-Vorgängen
Vor ODBC 3.8 wurde 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 What's New in ODBC 3.8.
Das asynchrone Ausführen von Verbindungsvorgängen ist in den folgenden Szenarien hilfreich:
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 reduzieren.
Effiziente asynchrone ODBC-Aufrufe und die Möglichkeit zum Abbrechen von Verbindungsvorgängen ermöglichen es einer Anwendung, dem Benutzer das Abbrechen eines langsamen Vorgangs zu ermöglichen, ohne auf Timeouts warten zu müssen.
Die folgenden Funktionen, die mit Verbindungshandles arbeiten, können jetzt asynchron ausgeführt werden:
Um festzustellen, 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 funktionen, die mit einer bestimmten Verbindung ausgeführt werden, asynchron ausgeführt werden sollen, ruft die Anwendung SQLSet Verbinden Attr 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. Der Vorgang, der das Verbindungsattribut SQL_ATTR_ASYNC_DBC_FUNCTIONS_ENABLE mit SQLSet festlegt Verbinden Attr wird immer synchron ausgeführt.
Eine Anwendung kann einen asynchronen Vorgang aktivieren, bevor eine Verbindung hergestellt wird. Da der Treiber-Manager nicht ermitteln kann, welcher Treiber vor dem Herstellen einer Verbindung verwendet werden soll, gibt der Treiber-Manager immer erfolg in SQLSet Verbinden Attr zurück. Es kann jedoch keine Verbindung herstellen, wenn der ODBC-Treiber keine asynchronen Vorgänge unterstützt.
Im Allgemeinen kann es höchstens eine asynchron ausgeführte Funktion geben, die einem bestimmten Verbindungsziehpunkt oder Anweisungshandle zugeordnet ist. Ein Verbindungshandle kann jedoch mehrere zugeordnete Anweisungshandle aufweisen. Wenn kein asynchroner Vorgang für das Verbindungshandle ausgeführt wird, kann ein zugeordneter Anweisungshandle einen asynchronen Vorgang ausführen. Ebenso können Sie über einen asynchronen Vorgang für ein Verbindungshandle verfügen, wenn keine asynchronen Vorgänge für ein zugehöriges Anweisungshandle ausgeführt werden. Ein Versuch, einen asynchronen Vorgang mithilfe eines Handles auszuführen, das derzeit einen asynchronen Vorgang ausführt, gibt HY010, "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 (im Verbindungshandle )
SQLGetDiagField
Sqlgetdiagrec
SQLAllocHandle (ENV/DBC zuordnen)
SQLAllocHandleStd (ENV/DBC zuordnen)
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, gibt sie die aktuelle Liste der Diagnosedatensätze zurück. Jedes Mal, wenn der ursprüngliche Funktionsaufruf wiederholt wird, werden vorherige Diagnosedatensätze gelöscht.
Wenn eine Verbindung asynchron geöffnet oder geschlossen wird, wird der Vorgang abgeschlossen, wenn die Anwendung SQL_SUCCESS oder SQL_SUCCESS_WITH_INFO im ursprünglichen Funktionsaufruf empfängt.
Zu ODBC 3.8, SQLCancelHandle, wurde eine neue Funktion hinzugefügt. Mit dieser Funktion werden die sechs Verbindungsfunktionen (SQLBrowse Verbinden, SQL Verbinden, SQLDisconnect, SQLDriver Verbinden, SQLEndTran und SQLSet Verbinden Attr) abgebrochen. 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 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 entspricht dem Aufrufen von SQLCancel.
Es ist nicht erforderlich, sowohl SQLCancelHandle- als auch asynchrone Verbindungsvorgänge gleichzeitig zu unterstützen. Ein Treiber kann asynchrone Verbindungsvorgänge, aber nicht SQLCancelHandle oder umgekehrt unterstützen.
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 zum Aktivieren einer älteren Anwendung für die Verwendung neuer Features in späterer ODBC-Version finden Sie unter Compatibility Matrix.
Verbindungspooling
Wenn verbindungspooling aktiviert ist, werden asynchrone Vorgänge nur minimal unterstützt, um eine Verbindung (mit SQL Verbinden und SQLDriver Verbinden) herzustellen und eine Verbindung mit SQLDisconnect zu schließen. Eine Anwendung sollte jedoch weiterhin in der Lage sein, den SQL_STILL_EXECUTING Rückgabewert von SQL Verbinden, SQLDriver Verbinden und SQLDisconnect zu verarbeiten.
Wenn verbindungspooling aktiviert ist, werden SQLEndTran und SQLSet Verbinden Attr für asynchrone Vorgänge unterstützt.
Beispiele
.A Aktivieren der asynchronen Ausführung von Verbindungsfunktionen
Das folgende Beispiel zeigt, wie Sie SQLSet Verbinden Attr 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;
}