Comparteix via


Ejecución asincrónica (método de sondeo)

Antes de ODBC 3.8 y el SDK de Windows 7, solo se permitían operaciones asincrónicas en funciones de declaración. Para obtener más información, vea Ejecución de Operaciones de Instrucciones Asincrónicamente, más adelante en este tema.

ODBC 3.8 en el SDK de Windows 7 introdujo la ejecución asincrónica en operaciones relacionadas con la conexión. Para obtener más información, consulte la sección Ejecución de operaciones de conexión de forma asincrónica , más adelante en este tema.

En el SDK de Windows 7, para operaciones de conexión o instrucciones asincrónicas, una aplicación determinó que la operación asincrónica se completó mediante el método de sondeo. A partir del SDK de Windows 8, puedes determinar que se completa una operación asincrónica mediante el método de notificación. Para obtener más información, vea Ejecución asincrónica (método de notificación).

De forma predeterminada, los controladores ejecutan funciones ODBC de forma sincrónica; es decir, la aplicación llama a una función y el controlador no devuelve el control a la aplicación hasta que haya terminado de ejecutar la función. Sin embargo, algunas funciones se pueden ejecutar de forma asincrónica; es decir, la aplicación llama a la función y el controlador, después del procesamiento mínimo, devuelve el control a la aplicación. A continuación, la aplicación puede llamar a otras funciones mientras la primera función sigue ejecutándose.

La ejecución asincrónica se admite para la mayoría de las funciones que se ejecutan en gran medida en el origen de datos, como las funciones para establecer conexiones, preparar y ejecutar instrucciones SQL, recuperar metadatos, capturar datos y confirmar transacciones. Resulta más útil cuando la tarea que se ejecuta en el origen de datos tarda mucho tiempo, como un proceso de inicio de sesión o una consulta compleja en una base de datos grande.

Cuando la aplicación ejecuta una función con una instrucción o conexión que está habilitada para el procesamiento asincrónico, el controlador realiza una cantidad mínima de procesamiento (como verificar si hay errores en los argumentos), traslada el procesamiento al origen de datos y devuelve el control a la aplicación con el código de retorno SQL_STILL_EXECUTING. A continuación, la aplicación realiza otras tareas. Para determinar cuándo ha finalizado la función asincrónica, la aplicación sondea el controlador a intervalos regulares llamando a la función con los mismos argumentos que usó originalmente. Si la función sigue ejecutándose, devuelve SQL_STILL_EXECUTING; Si ha terminado de ejecutarse, devuelve el código que habría devuelto si se hubiera ejecutado de forma sincrónica, como SQL_SUCCESS, SQL_ERROR o SQL_NEED_DATA.

Si una función se ejecuta de forma sincrónica o asincrónica es específica del controlador. Por ejemplo, supongamos que los metadatos del conjunto de resultados se almacenan en caché en el controlador. En este caso, se tarda muy poco tiempo en ejecutar SQLDescribeCol y el controlador simplemente debe ejecutar la función en lugar de retrasar artificialmente la ejecución. Por otro lado, si el controlador necesita recuperar los metadatos del origen de datos, debe devolver el control a la aplicación mientras lo hace. Por lo tanto, la aplicación debe ser capaz de controlar un código de retorno distinto de SQL_STILL_EXECUTING cuando ejecuta por primera vez una función de forma asincrónica.

Ejecutar operaciones con declaraciones de forma asincrónica

Las siguientes funciones de declaración operan en un origen de datos y pueden ejecutarse de manera asíncrona.

La ejecución de instrucciones asincrónicas se controla por instrucción o por conexión, en función del origen de datos. Es decir, la aplicación especifica no que una función determinada se ejecute de forma asincrónica, pero que cualquier función ejecutada en una instrucción determinada se ejecute de forma asincrónica. Para averiguar cuál es compatible, una aplicación llama a SQLGetInfo con una opción de SQL_ASYNC_MODE. SQL_AM_CONNECTION se devuelve si se admite la ejecución asincrónica de nivel de conexión (para un identificador de instrucción); SQL_AM_STATEMENT si se admite la ejecución asincrónica de nivel de instrucción.

Para especificar que las funciones ejecutadas con una instrucción determinada se ejecutarán de forma asincrónica, la aplicación llama a SQLSetStmtAttr con el atributo SQL_ATTR_ASYNC_ENABLE y la establece en SQL_ASYNC_ENABLE_ON. Si se admite el procesamiento asincrónico de nivel de conexión, el atributo de instrucción SQL_ATTR_ASYNC_ENABLE es de solo lectura y su valor es el mismo que el atributo de conexión de la conexión en la que se asignó la instrucción. Depende del controlador si el valor del atributo de instrucción se establece en el momento de la asignación de instrucciones o ya sea más tarde. Al intentar establecer, se devolverán SQL_ERROR y SQLSTATE HYC00 (característica opcional no implementada).

Para especificar que las funciones ejecutadas con una conexión determinada se ejecutarán de forma asincrónica, la aplicación llama a SQLSetConnectAttr con el atributo SQL_ATTR_ASYNC_ENABLE y la establece en SQL_ASYNC_ENABLE_ON. Todos los identificadores de instrucción futuros asignados en la conexión se habilitarán para la ejecución asincrónica; está definido por el controlador si esta acción habilitará los identificadores de instrucción existentes. Si SQL_ATTR_ASYNC_ENABLE se establece en SQL_ASYNC_ENABLE_OFF, todas las instrucciones de la conexión están en modo sincrónico. Se devuelve un error si la ejecución asincrónica está habilitada mientras hay una instrucción activa en la conexión.

Para determinar el número máximo de instrucciones simultáneas activas en modo asincrónico que el controlador puede admitir en una conexión determinada, la aplicación llama a SQLGetInfo con la opción SQL_MAX_ASYNC_CONCURRENT_STATEMENTS.

En el código siguiente se muestra cómo funciona el modelo de sondeo:

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.  

Mientras una función se ejecuta de forma asincrónica, la aplicación puede llamar a funciones en cualquier otra instrucción. La aplicación también puede llamar a funciones en cualquier conexión, excepto la asociada a la instrucción asincrónica. Pero la aplicación solo puede llamar a la función original y a las siguientes funciones (con el identificador de instrucción o su conexión asociada, identificador de entorno), después de que una operación de instrucción devuelva SQL_STILL_EXECUTING:

Si la aplicación llama a cualquier otra función con la instrucción asincrónica o con la conexión asociada a esa instrucción, la función devuelve SQLSTATE HY010 (error de secuencia de funciones), por ejemplo.

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  
}  

Cuando una aplicación llama a una función para determinar si todavía se está ejecutando de forma asincrónica, debe usar el identificador de instrucción original. Esto se debe a que la ejecución asincrónica se supervisa en función de cada instrucción. La aplicación también debe proporcionar valores válidos para los otros argumentos (los argumentos originales serán suficientes) para superar la comprobación de errores en el Gestor de Controladores. Sin embargo, después de que el controlador compruebe el identificador de instrucción y determine que la instrucción se está ejecutando de forma asincrónica, omite todos los demás argumentos.

Mientras una función se ejecuta de forma asincrónica, es decir, después de que haya devuelto SQL_STILL_EXECUTING y antes de que devuelva un código diferente, la aplicación puede cancelarla llamando a SQLCancel o SQLCancelHandle con el mismo identificador de instrucción. No se garantiza que esto cancele la ejecución de la función. Por ejemplo, es posible que la función ya haya terminado. Además, el código devuelto por SQLCancel o SQLCancelHandle solo indica si el intento de cancelar la función se realizó correctamente, no si realmente canceló la función. Para determinar si la función se canceló, la aplicación vuelve a llamar a la función. Si se canceló la función, devuelve SQL_ERROR y SQLSTATE HY008 (operación cancelada). Si no se canceló la función, devuelve otro código, como SQL_SUCCESS, SQL_STILL_EXECUTING o SQL_ERROR con un valor SQLSTATE diferente.

Para deshabilitar la ejecución asincrónica de una instrucción determinada cuando el controlador admite el procesamiento asincrónico de nivel de instrucción, la aplicación llama a SQLSetStmtAttr con el atributo SQL_ATTR_ASYNC_ENABLE y la establece en SQL_ASYNC_ENABLE_OFF. Si el controlador admite el procesamiento asincrónico de nivel de conexión, la aplicación llama a SQLSetConnectAttr para establecer SQL_ATTR_ASYNC_ENABLE en SQL_ASYNC_ENABLE_OFF, lo que deshabilita la ejecución asincrónica de todas las instrucciones en la conexión.

La aplicación debe procesar los registros de diagnóstico en el bucle de repetición de la función original. Si se llama a SQLGetDiagField o SQLGetDiagRec cuando se ejecuta una función asincrónica, devolverá la lista actual de registros de diagnóstico. Cada vez que se repite la llamada de función original, borra los registros de diagnóstico anteriores.

Ejecutar operaciones de conexión de forma asincrónica

Antes de ODBC 3.8, se permitía la ejecución asincrónica para operaciones relacionadas con instrucciones, como preparar, ejecutar y capturar, así como para las operaciones de metadatos del catálogo. A partir de ODBC 3.8, la ejecución asincrónica también es posible para las operaciones relacionadas con la conexión, como la conexión, la desconexión, la confirmación y la reversión.

Para obtener más información sobre ODBC 3.8, vea Novedades de ODBC 3.8.

La ejecución de operaciones de conexión de forma asincrónica es útil en los escenarios siguientes:

  • Cuando un pequeño número de subprocesos administra un gran número de dispositivos con tasas de datos muy altas. Para maximizar la capacidad de respuesta y la escalabilidad, es deseable que todas las operaciones sean asincrónicas.

  • Si desea superponer las operaciones de base de datos en varias conexiones para reducir los tiempos de transferencia transcurridos.

  • Las llamadas ODBC asincrónicas eficaces y la capacidad de cancelar las operaciones de conexión permiten que una aplicación permita al usuario cancelar cualquier operación lenta sin tener que esperar los tiempos de espera.

Las siguientes funciones, que funcionan en identificadores de conexión, ahora se pueden ejecutar de forma asincrónica:

Para determinar si un controlador admite operaciones asincrónicas en estas funciones, una aplicación llama a SQLGetInfo con SQL_ASYNC_DBC_FUNCTIONS. SQL_ASYNC_DBC_CAPABLE se devuelve si se admiten operaciones asincrónicas. SQL_ASYNC_DBC_NOT_CAPABLE se devuelve si no se admiten operaciones asincrónicas.

Para especificar que las funciones ejecutadas con una conexión determinada se ejecutarán de forma asincrónica, la aplicación llama a SQLSetConnectAttr y establece el atributo SQL_ATTR_ASYNC_DBC_FUNCTIONS_ENABLE en SQL_ASYNC_DBC_ENABLE_ON. Establecer un atributo de conexión antes de establecer una conexión siempre se ejecuta de forma sincrónica. Además, la operación que establece el atributo de conexión SQL_ATTR_ASYNC_DBC_FUNCTIONS_ENABLE con SQLSetConnectAttr siempre se ejecuta de forma sincrónica.

Una aplicación puede habilitar la operación asincrónica antes de realizar una conexión. Dado que el Administrador de controladores no puede determinar qué controlador usar antes de realizar una conexión, el Administrador de controladores siempre devolverá el éxito en SQLSetConnectAttr. Sin embargo, puede no conectarse si el controlador ODBC no admite operaciones asincrónicas.

En general, puede haber como máximo una función de ejecución asincrónica asociada a un identificador de conexión o identificador de instrucción determinado. Sin embargo, un identificador de conexión puede tener más de un identificador de instrucción asociado. Si no hay ninguna operación asincrónica que se ejecute en el identificador de conexión, un identificador de instrucción asociado puede ejecutar una operación asincrónica. De forma similar, puede tener una operación asincrónica en un identificador de conexión si no hay ninguna operación asincrónica en curso en ningún identificador de instrucción asociado. Un intento de ejecutar una operación asincrónica con un identificador que actualmente ejecuta una operación asincrónica devolverá HY010, "Error de secuencia de funciones".

Si una operación de conexión devuelve SQL_STILL_EXECUTING, una aplicación solo puede llamar a la función original y a las siguientes funciones para ese identificador de conexión:

  • SQLCancelHandle (en el identificador de conexión)

  • SQLGetDiagField

  • SQLGetDiagRec

  • SQLAllocHandle (asignación de ENV/DBC)

  • SQLAllocHandleStd (asignación de ENV/DBC)

  • SQLGetEnvAttr

  • SQLGetConnectAttr

  • SQLDataSources

  • SQLDrivers

  • SQLGetInfo

  • SQLGetFunctions

La aplicación debe procesar los registros de diagnóstico en el bucle de repetición de la función original. Si se llama a SQLGetDiagField o SQLGetDiagRec cuando se ejecuta una función asincrónica, devolverá la lista actual de registros de diagnóstico. Cada vez que se repite la llamada a la función original, se borran los registros de diagnóstico anteriores.

Si se abre o cierra una conexión de forma asincrónica, la operación se completa cuando la aplicación recibe SQL_SUCCESS o SQL_SUCCESS_WITH_INFO en la llamada de función original.

Se ha agregado una nueva función a ODBC 3.8, SQLCancelHandle. Esta función cancela las seis funciones de conexión (SQLBrowseConnect, SQLConnect, SQLDisconnect, SQLDriverConnect, SQLEndTran y SQLSetConnectAttr). Una aplicación debe llamar a SQLGetFunctions para determinar si el controlador admite SQLCancelHandle. Al igual que con SQLCancel, si SQLCancelHandle devuelve éxito, no significa que se canceló la operación. Una aplicación debe llamar a la función original de nuevo para determinar si se canceló la operación. SQLCancelHandle permite cancelar operaciones asincrónicas en identificadores de conexión o identificadores de instrucción. El uso de SQLCancelHandle para cancelar una operación en un identificador de instrucción es el mismo que llamar a SQLCancel.

No es necesario admitir las operaciones de conexión asincrónica y SQLCancelHandle al mismo tiempo. Un controlador puede admitir operaciones de conexión asincrónicas, pero no SQLCancelHandle, o viceversa.

Las operaciones de conexión asincrónica y SQLCancelHandle también se pueden usar en aplicaciones ODBC 3.x y ODBC 2.x con un controlador ODBC 3.8 y el Administrador de controladores ODBC 3.8. Para obtener información sobre cómo habilitar una aplicación anterior para usar nuevas características en versiones posteriores de ODBC, vea Matriz de compatibilidad.

Agrupar conexiones

Cada vez que la agrupación de conexiones está habilitada, las operaciones asincrónicas solo se admiten mínimamente para establecer una conexión (con SQLConnect y SQLDriverConnect) y cerrar una conexión con SQLDisconnect. Pero una aplicación todavía debe poder controlar el valor devuelto SQL_STILL_EXECUTING de SQLConnect, SQLDriverConnect y SQLDisconnect.

Cuando la agrupación de conexiones está habilitada, SQLEndTran y SQLSetConnectAttr se admiten para operaciones asincrónicas.

Examples

A. Habilitación de la ejecución asincrónica de funciones de conexión

En el ejemplo siguiente se muestra cómo usar SQLSetConnectAttr para habilitar la ejecución asincrónica para las funciones relacionadas con la conexión.

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. Operaciones de confirmación asincrónicas

En este ejemplo se muestran las operaciones de confirmación asincrónicas. Las operaciones de reversión también se pueden realizar de esta manera.

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;  
}  

Véase también

Ejecución de instrucciones ODBC