Nota
O acesso a esta página requer autorização. Podes tentar iniciar sessão ou mudar de diretório.
O acesso a esta página requer autorização. Podes tentar mudar de diretório.
Antes do ODBC 3.8 e do SDK do Windows 7, operações assíncronas eram permitidas apenas em funções de instruções. Para mais informações, consulte Execução de Operações de Instrução Assíncronas mais adiante neste tópico.
O ODBC 3.8 no SDK do Windows 7 introduziu a execução assíncrona em operações relacionadas com a ligação. Para mais informações, consulte a secção Executar Operações de Ligação Assíncronas , mais adiante neste tópico.
No SDK do Windows 7, para instruções assíncronas ou operações de ligação, uma aplicação determinava que a operação assíncrona estava completa usando o método de sondagem. A partir do SDK do Windows 8, pode determinar que uma operação assíncrona está completa usando o método de notificação. Para mais informações, consulte Execução Assíncrona (Método de Notificação).
Por defeito, os drivers executam funções ODBC de forma síncrona; ou seja, a aplicação chama uma função e o driver não devolve o controlo à aplicação até terminar de executar a função. No entanto, algumas funções podem ser executadas de forma assíncrona; ou seja, a aplicação chama a função, e o driver, após um processamento mínimo, devolve o controlo à aplicação. A aplicação pode então chamar outras funções enquanto a primeira função ainda está em execução.
A execução assíncrona é suportada para a maioria das funções que são maioritariamente executadas na fonte de dados, como as funções para estabelecer ligações, preparar e executar instruções SQL, recuperar metadados, recolher dados e fazer commit de transações. É mais útil quando a tarefa executada na fonte de dados demora muito tempo, como um processo de login ou uma consulta complexa numa grande base de dados.
Quando a aplicação executa uma função com uma instrução ou ligação ativada para processamento assíncrono, o driver realiza uma quantidade mínima de processamento (como verificar argumentos para erros), entregar o processamento à fonte de dados e devolve o controlo à aplicação com o código de retorno SQL_STILL_EXECUTING. A aplicação executa então outras tarefas. Para determinar quando a função assíncrona terminou, a aplicação interroga o driver a intervalos regulares, chamando a função com os mesmos argumentos que usou originalmente. Se a função ainda estiver em execução, devolve SQL_STILL_EXECUTING; Se terminou a execução, devolve o código que teria devolvido 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 depende do driver. Por exemplo, suponha que os metadados do conjunto de resultados estão armazenados em cache no driver. Neste caso, demora muito pouco tempo a executar o 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 de recuperar os metadados da fonte de dados, deve devolver o controlo à aplicação enquanto esta faz isso. Portanto, a aplicação deve ser capaz de gerir um código de retorno diferente de SQL_STILL_EXECUTING quando executa uma função pela primeira vez de forma assíncrona.
Execução de Operações de Instrução Assíncronas
As seguintes funções de declaração operam numa 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ções assíncronas é controlada por instrução ou por conexão, dependendo da fonte de dados. Ou seja, a aplicação especifica não que uma determinada função deve ser executada de forma assíncrona, mas que qualquer função executada numa determinada instrução deve ser executada de forma assíncrona. Para descobrir qual é suportado, uma aplicação chama SQLGetInfo com a opção de SQL_ASYNC_MODE. SQL_AM_CONNECTION é devolvido se a execução assíncrona ao nível da ligação (para um manipulador de instrução) for suportada; SQL_AM_STATEMENT se a execução assíncrona ao nível da instrução for suportada.
Para especificar que as funções executadas com uma determinada instrução devem ser executadas de forma assíncrona, a aplicação chama SQLSetStmtAttr com o atributo SQL_ATTR_ASYNC_ENABLE e define-o para SQL_ASYNC_ENABLE_ON. Se for suportado processamento assíncrono ao nível da ligação, o atributo da instrução SQL_ATTR_ASYNC_ENABLE é apenas leitura e o seu valor é o mesmo que o atributo de ligação da ligação à qual a instrução foi alocada. Depende do driver se o valor do atributo da instrução é definido no momento da alocação da instrução ou posteriormente. Ao tentar defini-lo, devolve SQL_ERROR e SQLSTATE HYC00 (funcionalidade opcional não implementada).
Para especificar que as funções executadas com uma ligação específica devem ser executadas de forma assíncrona, a aplicação chama SQLSetConnectAttr com o atributo SQL_ATTR_ASYNC_ENABLE e define-o para SQL_ASYNC_ENABLE_ON. Todos os futuros statement handles atribuídos na ligação serão habilitados para execução assíncrona; cabe ao driver definir se os statement handles existentes serão habilitados por esta ação. Se SQL_ATTR_ASYNC_ENABLE estiver definido para SQL_ASYNC_ENABLE_OFF, todas as instruções na ligação estão em modo síncrono. Um erro é devolvido se a execução assíncrona estiver ativada enquanto existe uma instrução ativa na ligação.
Para determinar o número máximo de instruções ativas concorrentes em modo assíncrono que o driver pode suportar numa dada ligação, a aplicação chama SQLGetInfo com a opção SQL_MAX_ASYNC_CONCURRENT_STATEMENTS.
O código seguinte demonstra como funciona o modelo de sondagem:
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á a ser executada de forma assíncrona, a aplicação pode chamar funções em quaisquer outras instruções. A aplicação também pode chamar funções em qualquer ligação, exceto aquela associada à instrução assíncrona. Mas a aplicação só pode chamar a função original e funções subsequentes (usando o handle da instrução ou a ligação associada, handle de ambiente), depois de uma operação da instrução devolver SQL_STILL_EXECUTING:
SQLCancelHandle (no handle da instrução)
Se a aplicação chamar qualquer outra função com a instrução assíncrona ou com a ligação associada a essa instrução, a função devolve, por exemplo, SQLSTATE HY010 (Function sequence error).
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 uma aplicação chama uma função para determinar se ainda está a ser executada de forma assíncrona, deve usar o handle original da instrução. Isto deve-se ao facto de a execução assíncrona ser monitorizada com base em cada instrução. A aplicação também deve fornecer valores válidos para os outros argumentos – os argumentos originais servirão – para ultrapassar a verificação de erros no Gestor de Drivers. No entanto, depois de o driver verificar a alavanca da instrução e determinar que a instrução está a ser executada de forma assíncrona, ignora todos os outros argumentos.
Enquanto uma função está a ser executada assíncrona – ou seja, depois de ter devolvido SQL_STILL_EXECUTING e antes de devolver um código diferente – a aplicação pode cancelá-la chamando SQLCancel ou SQLCancelHandle com o mesmo handle de instrução. Isto não garante que cancele a execução da função. Por exemplo, a função pode já ter terminado. Além disso, o código devolvido pelo SQLCancel ou SQLCancelHandle indica apenas se a tentativa de cancelar a função foi bem-sucedida, e não se efetivamente cancelou a função. Para determinar se a função foi cancelada, a aplicação chama novamente a função. Se a função foi cancelada, devolve SQL_ERROR e SQLSTATE HY008 (Operação cancelada). Se a função não for cancelada, devolve outro código, como SQL_SUCCESS, SQL_STILL_EXECUTING ou SQL_ERROR com um SQLSTATE diferente.
Para desativar a execução assíncrona de uma determinada instrução quando o driver suporta processamento assíncrono ao nível da instrução, a aplicação chama SQLSetStmtAttr com o atributo SQL_ATTR_ASYNC_ENABLE e define-o para SQL_ASYNC_ENABLE_OFF. Se o driver suportar processamento assíncrono ao nível da ligação, a aplicação chama 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 ligação.
A aplicação deve processar registos de diagnóstico no ciclo repetitivo da função original. Se o SQLGetDiagField ou SQLGetDiagRec for chamado quando uma função assíncrona está a ser executada, devolverá a lista atual de registos de diagnóstico. Cada vez que a chamada de função original é repetida, apaga os registos de diagnóstico anteriores.
Execução de Operações de Ligação Assíncronas
Antes do ODBC 3.8, a execução assíncrona era permitida para operações relacionadas com instruções, como preparar, executar e buscar, 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 com a conexão, como conectar, desconectar, confirmar e rollback.
Para mais informações sobre o ODBC 3.8, consulte O que há de novo no ODBC 3.8.
Executar operações de ligação de forma assíncrona é útil nos seguintes cenários:
Quando um pequeno número de threads está a gerir um grande número de dispositivos com taxas de dados muito elevadas. Para maximizar a capacidade de resposta e escalabilidade, é desejável que todas as operações sejam assíncronas.
Quando quiser realizar operações simultâneas de base de dados em múltiplas ligações para reduzir o tempo gasto com transferências.
Chamadas ODBC assíncronas eficientes e a capacidade de cancelar operações de ligação permitem que uma aplicação permita ao utilizador cancelar qualquer operação lenta sem ter de esperar por tempos de espera.
As seguintes funções, que operam em alavancas de ligação, podem agora ser executadas de forma assíncrona:
Para determinar se um driver suporta operações assíncronas nestas funções, uma aplicação chama SQLGetInfo com SQL_ASYNC_DBC_FUNCTIONS. SQL_ASYNC_DBC_CAPABLE é devolvido se forem suportadas operações assíncronas. SQL_ASYNC_DBC_NOT_CAPABLE é devolvido se operações assíncronas não forem suportadas.
Para especificar que as funções executadas com uma ligação específica devem ser executadas assíncronas, a aplicação chama SQLSetConnectAttr e define o atributo SQL_ATTR_ASYNC_DBC_FUNCTIONS_ENABLE para SQL_ASYNC_DBC_ENABLE_ON. Definir um atributo de ligação antes de estabelecer uma ligação é sempre executado de forma síncrona. Além disso, a operação que define o atributo de ligação SQL_ATTR_ASYNC_DBC_FUNCTIONS_ENABLE com SQLSetConnectAttr é sempre executada de forma síncrona.
Uma aplicação pode ativar a operação assíncrona antes de estabelecer uma ligação. Como o Gestor de Drivers não consegue determinar qual driver usar antes de estabelecer uma ligação, o Gestor de Drivers devolverá sempre sucesso em SQLSetConnectAttr. No entanto, pode falhar a ligação se o driver ODBC não suportar operações assíncronas.
Em geral, pode haver no máximo uma função em execução assíncrona associada a um determinado handle de ligação ou de instrução. No entanto, uma alça de conexão pode ter mais do que uma alça de instrução associada. Se não houver nenhuma operação assíncrona a ser executada no handle de ligação, um handle de instrução associado pode executar uma operação assíncrona. De forma semelhante, pode ter uma operação assíncrona num handle de ligação se não houver operações assíncronas em curso em qualquer handle de instrução associado. Uma tentativa de executar uma operação assíncrona usando um handle que esteja atualmente a executar uma operação assíncrona devolverá HY010, "Function sequence error".
Se uma operação de ligação devolver SQL_STILL_EXECUTING, uma aplicação só pode chamar a função original e as seguintes funções para esse handle de ligação:
SQLCancelHandle (na alavanca de ligação)
SQLGetDiagField
SQLGetDiagRec
SQLAllocHandle (atribuir ENV/DBC)
SQLAllocHandleStd (alocando ENV/DBC)
SQLGetEnvAttr
SQLGetConnectAttr
SQLDataSources
SQLDrivers
SQLGetInfo
SQLGetFunctions
A aplicação deve processar registos de diagnóstico no ciclo repetitivo da função original. Se o SQLGetDiagField ou SQLGetDiagRec for chamado quando uma função assíncrona está a ser executada, devolverá a lista atual de registos de diagnóstico. Cada vez que a chamada à função original é repetida, apaga os registos de diagnóstico anteriores.
Se uma ligação estiver a ser aberta ou fechada de forma assíncrona, a operação está concluída quando a aplicação recebe SQL_SUCCESS ou SQL_SUCCESS_WITH_INFO na chamada de função original.
Foi adicionada uma nova função ao ODBC 3.8, SQLCancelHandle. Esta função cancela as seis funções de ligação (SQLBrowseConnect, SQLConnect, SQLDisconnect, SQLDriverConnect, SQLEndTran e SQLSetConnectAttr). Uma aplicação deve chamar SQLGetFunctions para determinar se o driver suporta SQLCancelHandle. Tal como no SQLCancel, se o SQLCancelHandle devolver sucesso, isso não significa que a operação foi cancelada. Uma aplicação deve chamar novamente a função original para determinar se a operação foi cancelada. O SQLCancelHandle permite-lhe cancelar operações assíncronas em handles de ligação ou de instruções. Usar SQLCancelHandle para cancelar uma operação num handle de instrução é o mesmo que chamar SQLCancel.
Não é necessário suportar ao mesmo tempo SQLCancelHandle e operações de ligação assíncronas. Um driver pode suportar operações de ligação assíncronas, mas não SQLCancelHandle, ou vice-versa.
As operações de ligação assíncronas e o SQLCancelHandle também podem ser usados por aplicações ODBC 3.x e ODBC 2.x com um driver ODBC 3.8 e um gestor de drivers ODBC 3.8. Para informações sobre como permitir que uma aplicação mais antiga use novas funcionalidades numa versão posterior do ODBC, consulte Matriz de Compatibilidade.
Agrupamento de Conexões
Sempre que o pooling de ligações está ativado, operações assíncronas são apenas minimamente suportadas para estabelecer uma ligação (com SQLConnect e SQLDriverConnect) e fechar uma ligação com SQLDisconnect. Mas uma aplicação deve ainda ser capaz de gerir o valor de retorno SQL_STILL_EXECUTING do SQLConnect, SQLDriverConnect e SQLDisconnect.
Quando o pooling de ligações está ativado, SQLEndTran e SQLSetConnectAttr são suportados para operações assíncronas.
Examples
A. Permitir a execução assíncrona das funções de ligação
O exemplo seguinte mostra como usar SQLSetConnectAttr para permitir a execução assíncrona de funções relacionadas com a ligaçã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 commit assíncronas
Este exemplo mostra operações de commit assíncronas. As operações de rollback também podem ser feitas desta forma.
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;
}