Observação
O acesso a essa página exige autorização. Você pode tentar entrar ou alterar diretórios.
O acesso a essa página exige autorização. Você pode tentar alterar os diretórios.
Antes do ODBC 3.8 e do SDK do Windows 7, as operações assíncronas eram permitidas apenas em funções de instrução. Para obter mais informações, consulte Execução de Operações de Instrução Assíncronas, mais adiante neste tópico.
ODBC 3.8 no SDK do Windows 7 introduziu a execução assíncrona em operações relacionadas à conexão. Para obter mais informações, consulte a seção Executando operações de conexão de forma assíncrona , mais adiante neste tópico.
No SDK do Windows 7, para operações assíncronas de instrução ou conexão, um aplicativo determinava que a operação estava concluída usando o método de sondagem. A partir do SDK do Windows 8, você pode determinar que uma operação assíncrona está concluída usando o método de notificação. Para obter mais informações, consulte Execução assíncrona (método de notificação).
Por padrão, os drivers executam funções ODBC de forma síncrona; ou seja, o aplicativo chama uma função e o driver não retorna o controle para o aplicativo até concluir a execução da função. No entanto, algumas funções podem ser executadas de forma assíncrona; ou seja, o aplicativo chama a função e o driver, após o processamento mínimo, retorna o controle para o aplicativo. Em seguida, o aplicativo pode chamar outras funções enquanto a primeira função ainda estiver em execução.
A execução assíncrona tem suporte para a maioria das funções executadas em grande parte na fonte de dados, como as funções para estabelecer conexões, preparar e executar instruções SQL, recuperar metadados, buscar dados e confirmar transações. É mais útil quando a tarefa que está sendo executada na fonte de dados leva muito tempo, como um processo de logon ou uma consulta complexa em um banco de dados grande.
Quando o aplicativo executa uma função com uma instrução ou conexão habilitada para processamento assíncrono, o driver executa uma quantidade mínima de processamento (como a verificação de erros nos argumentos), delega o processamento à fonte de dados e retorna o controle ao aplicativo com o código de retorno SQL_STILL_EXECUTING. Em seguida, o aplicativo executa outras tarefas. Para determinar quando a função assíncrona foi concluída, o aplicativo sonda o driver em intervalos regulares chamando a função com os mesmos argumentos usados originalmente. Se a função ainda estiver em execução, ela retornará SQL_STILL_EXECUTING; se tiver concluído a execução, ele retornará o código que teria retornado se tivesse sido executado de forma síncrona, como SQL_SUCCESS, SQL_ERROR ou SQL_NEED_DATA.
Se uma função é executada de forma síncrona ou assíncrona é específico do driver. Por exemplo, suponha que os metadados do conjunto de resultados sejam armazenados em cache no driver. Nesse caso, leva muito pouco tempo para executar SQLDescribeCol e o driver deve simplesmente executar a função em vez de atrasar artificialmente a execução. Por outro lado, se o driver precisar recuperar os metadados da fonte de dados, ele deverá retornar o controle para o aplicativo enquanto ele estiver fazendo isso. Portanto, o aplicativo deve ser capaz de lidar com um código de retorno diferente de SQL_STILL_EXECUTING quando executa uma função de forma assíncrona pela primeira vez.
Execução de operações de instruções de forma assíncrona
As seguintes funções de declaração operam em uma fonte de dados e podem ser executadas de forma assíncrona:
SQLBulkOperations
Sqlcolattribute
Sqlcolumnprivileges
Sqlcolumns
Sqldescribecol
Sqldescribeparam
Sqlexecdirect
Sqlexecute
Sqlfetch
A execução de instrução assíncrona é controlada por instrução ou por conexão, dependendo da fonte de dados. Ou seja, o aplicativo não especifica que uma função específica deve ser executada de forma assíncrona, mas que qualquer função executada em uma instrução específica deve ser executada de forma assíncrona. Para descobrir qual deles tem suporte, um aplicativo chama SQLGetInfo com uma opção de SQL_ASYNC_MODE. SQL_AM_CONNECTION será retornado se houver suporte para execução assíncrona no nível da conexão (para um identificador de instrução) ; SQL_AM_STATEMENT se houver suporte para execução assíncrona no nível da instrução.
Para especificar que as funções executadas com uma instrução específica devem ser executadas de forma assíncrona, o aplicativo chama SQLSetStmtAttr com o atributo SQL_ATTR_ASYNC_ENABLE e o define como SQL_ASYNC_ENABLE_ON. Se houver suporte para processamento assíncrono no nível da conexão, o atributo de instrução SQL_ATTR_ASYNC_ENABLE será somente leitura e seu valor será o mesmo que o atributo de conexão da conexão na qual a instrução foi alocada. É específico do driver se o valor do atributo de instrução é definido no momento da alocação da instrução ou em um momento posterior. Tentar defini-lo retornará SQL_ERROR e SQLSTATE HYC00 (recurso opcional não implementado).
Para especificar que as funções executadas com uma conexão específica devem ser executadas de forma assíncrona, o aplicativo chama SQLSetConnectAttr com o atributo SQL_ATTR_ASYNC_ENABLE e o define como SQL_ASYNC_ENABLE_ON. Todos os identificadores de instrução futuros alocados na conexão serão habilitados para execução assíncrona; é definido pelo driver se os identificadores de instrução existentes serão habilitados por essa ação. Se SQL_ATTR_ASYNC_ENABLE estiver definido como SQL_ASYNC_ENABLE_OFF, todas as instruções na conexão estarão no modo síncrono. Um erro será retornado se a execução assíncrona estiver habilitada enquanto houver uma instrução ativa na conexão.
Para determinar o número máximo de instruções simultâneas ativas no modo assíncrono que o driver pode dar suporte em uma determinada conexão, o aplicativo chama SQLGetInfo com a opção SQL_MAX_ASYNC_CONCURRENT_STATEMENTS.
O código a seguir demonstra como o modelo de sondagem funciona:
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.
Enquanto uma função está sendo executada de forma assíncrona, o aplicativo pode chamar funções em qualquer outra instrução. O aplicativo também pode chamar funções em qualquer conexão, exceto aquela associada à instrução assíncrona. Mas o aplicativo só pode chamar a função original e as seguintes funções (como o identificador de instrução ou a conexão associada, o identificador de ambiente) depois que uma operação de instrução retorna SQL_STILL_EXECUTING.
SQLCancelHandle (no identificador de instrução)
Se o aplicativo chamar qualquer outra função com a instrução assíncrona ou com a conexão associada a essa instrução, a função retornará SQLSTATE HY010 (erro de sequência de funções), por exemplo.
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
}
Quando um aplicativo chama uma função para determinar se ela ainda está em execução de forma assíncrona, ela deve usar o identificador de instrução original. Isso ocorre porque a execução assíncrona é controlada por instrução. O aplicativo também deve fornecer valores válidos para os outros argumentos – os argumentos originais serão usados – para obter verificação de erro anterior no Gerenciador de Driver. No entanto, depois que o driver verifica o identificador da instrução e determina que a instrução está sendo executada de forma assíncrona, ela ignora todos os outros argumentos.
Enquanto uma função está sendo executada de forma assíncrona, ou seja, depois de retornar SQL_STILL_EXECUTING e antes de retornar um código diferente, o aplicativo pode cancelá-la chamando SQLCancel ou SQLCancelHandle com o mesmo identificador de instrução. Isso não garante o cancelamento da execução da função. Por exemplo, a função pode já ter sido concluída. Além disso, o código retornado por SQLCancel ou SQLCancelHandle indica apenas se a tentativa de cancelar a função foi bem-sucedida, não se ela realmente cancelou a função. Para determinar se a função foi cancelada, o aplicativo chama a função novamente. Se a função tiver sido cancelada, ela retornará SQL_ERROR e SQLSTATE HY008 (Operação cancelada). Se a função não tiver sido cancelada, ela retornará outro código, como SQL_SUCCESS, SQL_STILL_EXECUTING ou SQL_ERROR com um SQLSTATE diferente.
Para desabilitar a execução assíncrona de uma instrução específica quando o driver dá suporte ao processamento assíncrono no nível da instrução, o aplicativo chama SQLSetStmtAttr com o atributo SQL_ATTR_ASYNC_ENABLE e o define como SQL_ASYNC_ENABLE_OFF. Se o driver der suporte ao processamento assíncrono no nível da conexão, o aplicativo chamará SQLSetConnectAttr para definir SQL_ATTR_ASYNC_ENABLE como SQL_ASYNC_ENABLE_OFF, o que desabilita a execução assíncrona de todas as instruções na conexão.
O aplicativo deve processar registros de diagnóstico no loop repetido da função original. Se SQLGetDiagField ou SQLGetDiagRec for chamado quando uma função assíncrona estiver em execução, ela retornará a lista atual de registros de diagnóstico. Sempre que a chamada de função original for repetida, ela limpará os registros de diagnóstico anteriores.
Executando operações de conexão de forma assíncrona
Antes do ODBC 3.8, a execução assíncrona era permitida para operações relacionadas a instruções, como preparação, execução e leitura de dados, bem como para operações de metadados de catálogo. A partir do ODBC 3.8, a execução assíncrona também é possível para operações relacionadas à conexão, como conexão, desconexão, confirmação e reversão.
Para obter mais informações sobre o ODBC 3.8, consulte As novidades no ODBC 3.8.
Executar operações de conexão de forma assíncrona é útil nos seguintes cenários:
Quando um pequeno número de threads gerencia um grande número de dispositivos, com taxas de dados muito altas. Para maximizar a capacidade de resposta e a escalabilidade, é desejável que todas as operações sejam assíncronas.
Quando você deseja sobrepor operações de banco de dados em várias conexões para reduzir os tempos de transferência.
Chamadas ODBC assíncronas eficientes e a capacidade de cancelar operações de conexão permitem que o usuário cancele qualquer operação lenta sem precisar esperar por tempos limite.
As seguintes funções, que operam em identificadores de conexão, agora podem ser executadas de forma assíncrona:
Para determinar se um driver dá suporte a operações assíncronas nessas funções, um aplicativo chama SQLGetInfo com SQL_ASYNC_DBC_FUNCTIONS. SQL_ASYNC_DBC_CAPABLE será retornado se houver suporte para operações assíncronas. SQL_ASYNC_DBC_NOT_CAPABLE será retornado se não houver suporte para operações assíncronas.
Para especificar que as funções executadas com uma conexão específica devem ser executadas de forma assíncrona, o aplicativo chama SQLSetConnectAttr e define o atributo SQL_ATTR_ASYNC_DBC_FUNCTIONS_ENABLE como SQL_ASYNC_DBC_ENABLE_ON. Definir um atributo de conexão antes de estabelecer uma conexão sempre é executado de forma síncrona. Além disso, a operação que define o atributo de conexão SQL_ATTR_ASYNC_DBC_FUNCTIONS_ENABLE com SQLSetConnectAttr sempre é executada de forma síncrona.
Um aplicativo pode habilitar a operação assíncrona antes de fazer uma conexão. Como o Gerenciador de Driver não pode determinar qual driver usar antes de fazer uma conexão, o Gerenciador de Driver sempre retornará êxito no SQLSetConnectAttr. No entanto, ele poderá falhar ao se conectar se o driver ODBC não der suporte a operações assíncronas.
Em geral, pode haver no máximo uma função de execução assíncrona associada a um identificador de conexão ou identificador de instrução específico. No entanto, um identificador de conexão pode ter mais de um identificador de instrução associado. Se não houver nenhuma operação assíncrona em execução no identificador de conexão, um identificador de instrução associado poderá executar uma operação assíncrona. Da mesma forma, você poderá ter uma operação assíncrona em um manipulador de conexão se não houver operações assíncronas em andamento em qualquer manipulador de instrução associado. Uma tentativa de executar uma operação assíncrona usando um manipulador que já está executando uma operação assíncrona retornará HY010, "Erro de sequência de funções".
Se uma operação de conexão retornar SQL_STILL_EXECUTING, um aplicativo só poderá chamar a função original e as seguintes funções para esse identificador de conexão:
SQLCancelHandle (no identificador de conexão)
Sqlgetdiagfield
Sqlgetdiagrec
SQLAllocHandle (alocando ENV/DBC)
SQLAllocHandleStd (alocando ENV/DBC)
SQLGetEnvAttr
Sqlgetconnectattr
SQLDataSources
SQLDrivers
Sqlgetinfo
Sqlgetfunctions
O aplicativo deve processar registros de diagnóstico no loop repetido da função original. Se SQLGetDiagField ou SQLGetDiagRec for chamado quando uma função assíncrona estiver em execução, ela retornará a lista atual de registros de diagnóstico. Sempre que a chamada de função original for repetida, ela limpará os registros de diagnóstico anteriores.
Se uma conexão estiver sendo aberta ou fechada de forma assíncrona, a operação será concluída quando o aplicativo receber SQL_SUCCESS ou SQL_SUCCESS_WITH_INFO na chamada de função original.
Uma nova função foi adicionada ao ODBC 3.8, SQLCancelHandle. Essa função cancela as seis funções de conexão (SQLBrowseConnect, SQLConnect, SQLDisconnect, SQLDriverConnect, SQLEndTran e SQLSetConnectAttr). Um aplicativo deve chamar SQLGetFunctions para determinar se o driver dá suporte a SQLCancelHandle. Assim como no SQLCancel, se SQLCancelHandle retornar êxito , isso não significa que a operação foi cancelada. Um aplicativo deve chamar a função original novamente para determinar se a operação foi cancelada. O SQLCancelHandle permite cancelar operações assíncronas em identificadores de conexão ou identificadores de instrução. Usar SQLCancelHandle para cancelar uma operação em um identificador de instrução é o mesmo que chamar SQLCancel.
Não é necessário dar suporte a SQLCancelHandle e operações de conexão assíncrona ao mesmo tempo. Um driver pode dar suporte a operações de conexão assíncronas, mas não SQLCancelHandle ou vice-versa.
As operações de conexão assíncrona e SQLCancelHandle também podem ser usadas por aplicativos ODBC 3.x e ODBC 2.x com um driver ODBC 3.8 e o Gerenciador de Driver ODBC 3.8. Para obter informações sobre como habilitar um aplicativo mais antigo a usar novos recursos na versão posterior do ODBC, consulte Matriz de Compatibilidade.
Pool de conexões
Sempre que o pool de conexões estiver habilitado, as operações assíncronas só têm suporte mínimo para estabelecer uma conexão (com SQLConnect e SQLDriverConnect) e fechar uma conexão com o SQLDisconnect. Mas um aplicativo ainda deve ser capaz de lidar com o valor retornado SQL_STILL_EXECUTING do SQLConnect, SQLDriverConnect e SQLDisconnect.
Quando o pool de conexões está habilitado, há suporte para SQLEndTran e SQLSetConnectAttr para operações assíncronas.
Exemplos
A. Habilitar a execução assíncrona de funções de conexão
O exemplo a seguir mostra como usar SQLSetConnectAttr para habilitar a execução assíncrona para funções relacionadas à conexão.
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. Operações de confirmação assíncronas
Este exemplo mostra operações de confirmação assíncronas. As operações de reversão também podem ser feitas dessa maneira.
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;
}