Примечание.
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
До ODBC 3.8 и пакета SDK для Windows 7 асинхронные операции были разрешены только для функций инструкций. Дополнительные сведения см. в разделе Асинхронное выполнение операций с инструкциями, который рассматривается далее в этом разделе.
В пакете SDK для Windows 7 в ODBC 3.8 было введено асинхронное выполнение операций, связанных с подключением. Дополнительные сведения см. в разделе "Выполнение операций асинхронного подключения " далее в этом разделе.
В Windows 7 SDK приложение использовало метод опроса, чтобы определить, что асинхронные операции с инструкциями или подключениями были завершены. Начиная с пакета SDK для Windows 8, можно определить, что асинхронная операция завершена с помощью метода уведомления. Дополнительные сведения см. в разделе "Асинхронное выполнение" (метод уведомления).
По умолчанию драйверы выполняют функции ODBC синхронно; То есть приложение вызывает функцию, и драйвер не возвращает управление приложению, пока он не завершит выполнение функции. Однако некоторые функции можно выполнять асинхронно; То есть приложение вызывает функцию, а драйвер после минимальной обработки возвращает управление приложению. Затем приложение может вызывать другие функции, пока первая функция по-прежнему выполняется.
Асинхронное выполнение поддерживается для большинства функций, которые в основном выполняются в источнике данных, таких как функции для установления подключений, подготовки и выполнения инструкций SQL, получения метаданных, получения данных и фиксации транзакций. Наиболее полезно, если задача, выполняемая в источнике данных, занимает много времени, например процесс входа или сложный запрос к большой базе данных.
Когда приложение выполняет функцию со встроенным оператором или подключением, поддерживающим асинхронную обработку, драйвер выполняет минимальную обработку (например, проверку аргументов на наличие ошибок), передает управление источнику данных и возвращает управление приложению с кодом возврата SQL_STILL_EXECUTING. Затем приложение выполняет другие задачи. Чтобы определить, когда асинхронная функция завершена, приложение опрашивает драйвер через регулярные интервалы, вызывая функцию с теми же аргументами, что и первоначально используемые. Если функция по-прежнему выполняется, она возвращает SQL_STILL_EXECUTING; Если он завершил выполнение, он возвращает код, который он возвратил, если бы он выполнялся синхронно, например SQL_SUCCESS, SQL_ERROR или SQL_NEED_DATA.
Будет ли функция выполняться синхронно или асинхронно, зависит от драйвера. Например, предположим, что метаданные результирующих наборов кэшируются в драйвере. В этом случае требуется очень мало времени для выполнения SQLDescribeCol , а драйвер должен просто выполнить функцию, а не искусственно отложить выполнение. С другой стороны, если драйверу необходимо получить метаданные из источника данных, он должен вернуть управление приложению во время выполнения этого. Поэтому приложение должно иметь возможность обрабатывать возвращаемый код, отличный от SQL_STILL_EXECUTING при первом выполнении функции асинхронно.
Выполнение операций операторов асинхронно
Следующие функции инструкции работают с источником данных и могут выполняться асинхронно:
SQLBulkOperations
SQLColAttribute
SQLColumnPrivileges
Sqlcolumns
SQLDescribeCol
SQLDescribeParam
SQLExecDirect
SQLExecute
SQLFetch
Асинхронное выполнение инструкций контролируется либо на уровне оператора, либо на уровне подключения, в зависимости от источника данных. То есть приложение указывает не то, что определенная функция должна выполняться асинхронно, но любая функция, выполняемая в определенной инструкции, должна выполняться асинхронно. Чтобы узнать, какой из них поддерживается, приложение вызывает SQLGetInfo с возможностью SQL_ASYNC_MODE. SQL_AM_CONNECTION возвращается, если поддерживается асинхронное выполнение на уровне подключения (для дескриптора инструкции); SQL_AM_STATEMENT, если асинхронное выполнение на уровне инструкций поддерживается.
Чтобы указать, что функции, выполняемые с определенной инструкцией, необходимо выполнять асинхронно, приложение вызывает SQLSetStmtAttr с атрибутом SQL_ATTR_ASYNC_ENABLE и задает для него значение SQL_ASYNC_ENABLE_ON. Если асинхронная обработка на уровне подключения поддерживается, атрибут инструкции SQL_ATTR_ASYNC_ENABLE доступен только для чтения, и его значение совпадает с атрибутом подключения, для которого выделена инструкция. Оно специфично для драйвера, задано ли значение атрибута инструкции во время выделения инструкции или позже. Попытка задать его возвращает SQL_ERROR и SQLSTATE HYC00 (необязательная функция не реализована).
Чтобы указать, что функции, выполняемые с определенным подключением, выполняются асинхронно, приложение вызывает SQLSetConnectAttr с атрибутом SQL_ATTR_ASYNC_ENABLE и задает для него значение SQL_ASYNC_ENABLE_ON. Все дескрипторы будущих инструкций, выделенные на подключении, будут включены для асинхронного выполнения; будет ли это действие распространяться на существующие дескрипторы инструкций, зависит от драйвера. Если для SQL_ATTR_ASYNC_ENABLE задано значение SQL_ASYNC_ENABLE_OFF, все операторы подключения находятся в синхронном режиме. Ошибка возвращается, если включен режим асинхронного выполнения при наличии активного запроса на соединении.
Чтобы определить максимальное количество активных одновременных инструкций в асинхронном режиме, которое драйвер может поддерживать в заданном соединении, приложение вызывает SQLGetInfo с параметром SQL_MAX_ASYNC_CONCURRENT_STATEMENTS.
В следующем коде показано, как работает модель опроса:
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.
Хотя функция выполняется асинхронно, приложение может вызывать функции в любых других выражениях. Приложение также может вызывать функции в любом соединении, за исключением одного, связанного с асинхронной инструкцией. Но приложение может вызывать исходную функцию и следующие функции (используя дескриптор инструкции или связанный с ней дескриптор подключения или дескриптор среды), после того как операция выполнения инструкции возвращает SQL_STILL_EXECUTING:
SQLCancelHandle (в дескрипторе инструкции)
Если приложение вызывает любую другую функцию с асинхронной инструкцией или подключением, связанной с этой инструкцией, функция возвращает SQLSTATE HY010 (ошибка последовательности функций), например.
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
}
Когда приложение вызывает функцию, чтобы определить, выполняется ли она асинхронно, она должна использовать дескриптор исходной инструкции. Это связано с тем, что асинхронное выполнение отслеживается для каждой инструкции. Приложение также должно указать допустимые значения для других аргументов — исходные аргументы подойдут — чтобы пройти проверку ошибок в диспетчере драйверов. Однако после проверки дескриптора инструкции драйвер определяет, что оператор выполняется асинхронно, он игнорирует все остальные аргументы.
Пока функция выполняется асинхронно, то есть после возвращения SQL_STILL_EXECUTING и до того, как возвратится другой код, приложение может отменить выполнение функции, вызвав SQLCancel или SQLCancelHandle с тем же дескриптором инструкции. Это не гарантирует отмену выполнения функции. Например, функция, возможно, уже завершена. Кроме того, код, возвращаемый SQLCancel или SQLCancelHandle, указывает, была ли попытка отменить функцию успешно, а не была ли она фактически отменена. Чтобы определить, была ли отменена функция, приложение снова вызывает функцию. Если функция была отменена, она возвращает SQL_ERROR и SQLSTATE HY008 (операция отменена). Если функция не была отменена, она возвращает другой код, например SQL_SUCCESS, SQL_STILL_EXECUTING или SQL_ERROR с другим SQLSTATE.
Чтобы отключить асинхронное выполнение конкретной инструкции, если драйвер поддерживает асинхронную обработку уровня инструкций, приложение вызывает SQLSetStmtAttr с атрибутом SQL_ATTR_ASYNC_ENABLE и задает для него значение SQL_ASYNC_ENABLE_OFF. Если драйвер поддерживает асинхронную обработку на уровне подключения, приложение вызывает SQLSetConnectAttr, чтобы установить SQL_ATTR_ASYNC_ENABLE в SQL_ASYNC_ENABLE_OFF, что отключает асинхронное выполнение всех инструкций на уровне соединения.
Приложение должно обрабатывать диагностические записи в повторяющемся цикле исходной функции. Если SQLGetDiagField или SQLGetDiagRec вызывается при выполнении асинхронной функции, он вернет текущий список диагностических записей. При каждом повторном вызове исходной функции он очищает предыдущие диагностические записи.
Выполнение операций подключения асинхронно
До ODBC 3.8 асинхронное выполнение было разрешено для операций, связанных с инструкцией, таких как подготовка, выполнение и извлечение, а также для операций метаданных каталога. Начиная с ODBC 3.8 асинхронное выполнение также возможно для операций, связанных с подключением, отключением, фиксацией и откатом.
Дополнительные сведения об ODBC 3.8 см. в статье "Новые возможности ODBC 3.8".
Выполнение операций подключения асинхронно полезно в следующих сценариях:
Если небольшое количество потоков управляет большим количеством устройств с очень высокой скоростью передачи данных. Чтобы максимально повысить скорость реагирования и масштабируемость, желательно, чтобы все операции были асинхронными.
Когда вы хотите накладывать операции с базой данных на несколько подключений, чтобы уменьшить общее время передачи.
Эффективные асинхронные вызовы ODBC и возможность отмены процессов подключения позволяют приложению дать пользователю возможность отменять любые медленные операции без ожидания тайм-аутов.
Теперь можно выполнять асинхронно следующие функции, которые работают с дескрипторами подключения.
Чтобы определить, поддерживает ли драйвер асинхронные операции с этими функциями, приложение вызывает SQLGetInfo с SQL_ASYNC_DBC_FUNCTIONS. SQL_ASYNC_DBC_CAPABLE возвращается, если поддерживаются асинхронные операции. SQL_ASYNC_DBC_NOT_CAPABLE возвращается, если асинхронные операции не поддерживаются.
Чтобы указать, что функции, выполняемые с определенным подключением, выполняются асинхронно, приложение вызывает SQLSetConnectAttr и задает атрибут SQL_ATTR_ASYNC_DBC_FUNCTIONS_ENABLE для SQL_ASYNC_DBC_ENABLE_ON. Установка атрибута подключения перед установкой соединения всегда выполняется синхронно. Операция установки атрибута подключения SQL_ATTR_ASYNC_DBC_FUNCTIONS_ENABLE с помощью SQLSetConnectAttr всегда выполняется синхронно.
Приложение может включить асинхронную операцию перед подключением. Так как диспетчер драйверов не может определить, какой драйвер следует использовать перед подключением, диспетчер драйверов всегда возвращает успех в SQLSetConnectAttr. Однако не удается подключиться, если драйвер ODBC не поддерживает асинхронные операции.
Как правило, может быть не более одной асинхронной функции, связанной с определенным дескриптором соединения или дескриптором инструкции. Однако дескриптор подключения может иметь несколько связанных дескрипторов инструкций. Если на дескрипторе соединения нет асинхронной операции, связанный дескриптор инструкции может выполнять асинхронную операцию. Аналогичным образом можно использовать асинхронную операцию в дескрипторе подключения, если не выполняются асинхронные операции в любом связанном дескрипторе инструкции. Попытка выполнить асинхронную операцию с помощью дескриптора, который в настоящее время выполняет асинхронную операцию, приведет к возврату HY010, "Ошибка последовательности функций".
Если операция подключения возвращает SQL_STILL_EXECUTING, приложение может вызывать только исходную функцию и следующие функции для этого дескриптора подключения:
SQLCancelHandle (в дескрипторе подключения)
SQLGetDiagField
SQLGetDiagRec
SQLAllocHandle (выделение ENV/DBC)
SQLAllocHandleStd (выделение ENV/DBC)
SQLGetEnvAttr
SQLGetConnectAttr
SQLDataSources
SQLDrivers
SQLGetInfo
SQLGetFunctions
Приложение должно обрабатывать диагностические записи в повторяющемся цикле исходной функции. Если SQLGetDiagField или SQLGetDiagRec вызывается при выполнении асинхронной функции, он вернет текущий список диагностических записей. При каждом повторном вызове исходной функции он очищает предыдущие диагностические записи.
Если соединение открыто или закрыто асинхронно, операция завершается, когда приложение получает SQL_SUCCESS или SQL_SUCCESS_WITH_INFO в исходном вызове функции.
В ODBC 3.8 добавлена новая функция SQLCancelHandle. Эта функция отменяет шесть функций подключения (SQLBrowseConnect, SQLConnect, SQLDisconnect, SQLDriverConnect, SQLEndTran и SQLSetConnectAttr). Приложение должно вызывать SQLGetFunctions , чтобы определить, поддерживает ли драйвер SQLCancelHandle. Как и в случае с SQLCancel, если SQLCancelHandle возвращает успех, это не означает, что операция была отменена. Приложение должно снова вызвать исходную функцию, чтобы определить, была ли отменена операция. SQLCancelHandle позволяет отменить асинхронные операции с дескрипторами подключения или дескрипторами инструкций. Использование SQLCancelHandle для отмены операции с дескриптором инструкции совпадает с вызовом SQLCancel.
Одновременно не требуется поддерживать как sqlCancelHandle, так и асинхронные операции подключения. Драйвер может поддерживать асинхронные операции подключения, но не SQLCancelHandle или наоборот.
Асинхронные операции подключения и SQLCancelHandle также могут использоваться приложениями ODBC 3.x и ODBC 2.x с драйвером ODBC 3.8 и диспетчером драйверов ODBC 3.8. Сведения о том, как разрешить более старому приложению использовать новые функции в более поздней версии ODBC, см. в таблице совместимости.
Пул подключений
При включении пула подключений асинхронные операции поддерживаются только минимально для установления соединения (с SQLConnect и SQLDriverConnect) и закрытия подключения к SQLDisconnect. Но приложение все еще должно иметь возможность обрабатывать возвращаемое значение SQL_STILL_EXECUTING из SQLConnect, SQLDriverConnect и SQLDisconnect.
При включении пула подключений SQLEndTran и SQLSetConnectAttr поддерживаются для асинхронных операций.
Примеры
А. Включение асинхронного выполнения функций подключения
В следующем примере показано, как использовать SQLSetConnectAttr для включения асинхронного выполнения для функций, связанных с подключением.
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;
}
В. Асинхронные операции фиксации
В этом примере показаны асинхронные операции фиксации. Операции отката также можно выполнить таким образом.
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;
}