Асинхронное выполнение (метод опроса)
До ODBC 3.8 и пакета SDK для Windows 7 асинхронные операции были разрешены только для функций инструкций. Дополнительные сведения см . в асинхронном режиме выполнения операций инструкций, приведенных далее в этом разделе.
ODBC 3.8 в пакете SDK для Windows 7 появилось асинхронное выполнение операций, связанных с подключением. Дополнительные сведения см. в разделе "Выполнение операций Подключение ion асинхронно" далее в этом разделе.
В пакете SDK для Windows 7 для асинхронных инструкций или операций подключения приложение определило, что асинхронная операция была завершена с помощью метода опроса. Начиная с пакета 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 (необязательная функция не реализована).
Чтобы указать, что функции, выполняемые с определенным подключением, выполняются асинхронно, приложение вызывает SQLSet Подключение Attr с атрибутом 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. Если драйвер поддерживает асинхронную обработку на уровне подключения, приложение вызывает SQLSet Подключение Attr, чтобы задать SQL_ATTR_ASYNC_ENABLE значение SQL_ASYNC_ENABLE_OFF, что отключает асинхронное выполнение всех инструкций подключения.
Приложение должно обрабатывать диагностические записи в повторяющийся цикл исходной функции. Если SQLGetDiagField или SQLGetDiagRec вызывается при выполнении асинхронной функции, он вернет текущий список диагностических записей. При каждом повторном вызове исходной функции он очищает предыдущие диагностические записи.
Выполнение операций Подключение ion асинхронно
До 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 возвращается, если асинхронные операции не поддерживаются.
Чтобы указать, что функции, выполняемые с определенным подключением, выполняются асинхронно, приложение вызывает SQLSet Подключение Attr и задает атрибут SQL_ATTR_ASYNC_DBC_FUNCTIONS_ENABLE для SQL_ASYNC_DBC_ENABLE_ON. Установка атрибута подключения перед установкой соединения всегда выполняется синхронно. Кроме того, операция, задав атрибут подключения SQL_ATTR_ASYNC_DBC_FUNCTIONS_ENABLE с ПОМОЩЬЮ SQLSet Подключение Attr всегда выполняется синхронно.
Приложение может включить асинхронную операцию перед подключением. Так как диспетчер драйверов не может определить, какой драйвер следует использовать перед подключением, диспетчер драйверов всегда возвращает успех в SQLSet Подключение Attr. Однако не удается подключиться, если драйвер 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. Эта функция отменяет шесть функций подключения (SQLBrowse Подключение, SQL Подключение, SQLDisconnect, SQLDriver Подключение, SQLEndTran и SQLSet Подключение Attr). Приложение должно вызывать SQLGetFunctions, чтобы определить, поддерживает ли драйвер SQLCancelHandle. Как и в случае с SQLCancel, если SQLCancelHandle возвращает успех, это не означает, что операция была отменена. Приложение должно снова вызвать исходную функцию, чтобы определить, была ли отменена операция. SQLCancelHandle позволяет отменить асинхронные операции с дескрипторами подключения или дескрипторами инструкций. Использование SQLCancelHandle для отмены операции с дескриптором инструкции совпадает с вызовом SQLCancel.
Одновременно не требуется поддерживать как sqlCancelHandle, так и асинхронные операции подключения. Драйвер может поддерживать асинхронные операции подключения, но не SQLCancelHandle или наоборот.
Асинхронные операции подключения и SQLCancelHandle также могут использоваться приложениями ODBC 3.x и ODBC 2.x с драйвером ODBC 3.8 и диспетчером драйверов ODBC 3.8. Сведения о том, как разрешить более старому приложению использовать новые функции в более поздней версии ODBC, см. в таблице совместимости.
Объединение подключений в пул
При включении пула подключений асинхронные операции поддерживаются только минимально для установления соединения (с SQL Подключение и SQLDriver Подключение) и закрытия подключения к SQLDisconnect. Но приложение по-прежнему должно обрабатывать возвращаемое значение SQL_STILL_EXECUTING из SQL Подключение, SQLDriver Подключение и SQLDisconnect.
Если пул подключений включен, SQLEndTran и SQLSet Подключение Attr поддерживаются для асинхронных операций.
Примеры
А. Включение асинхронного выполнения функций подключения
В следующем примере показано, как использовать SQLSet Подключение Attr для включения асинхронного выполнения для функций, связанных с подключением.
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. Асинхронные операции фиксации
В этом примере показаны асинхронные операции фиксации. Операции отката также можно сделать таким образом.
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;
}