Condividi tramite


Esecuzione asincrona (metodo di polling)

Prima di ODBC 3.8 e Windows 7 SDK, le operazioni asincrone erano consentite solo sulle funzioni di istruzione. Per altre informazioni, vedere Esecuzione asincrona di operazioni di istruzione più avanti in questo argomento.

ODBC 3.8 in Windows 7 SDK ha introdotto l'esecuzione asincrona nelle operazioni correlate alla connessione. Per altre informazioni, vedere la sezione Esecuzione di operazioni di connessione in modo asincrono , più avanti in questo argomento.

Nel Windows 7 SDK, per le istruzioni o operazioni di connessione asincrone, un'applicazione ha determinato che l'operazione asincrona fosse completata usando il metodo di polling. A partire da Windows 8 SDK, è possibile determinare che un'operazione asincrona è stata completata usando il metodo di notifica. Per altre informazioni, vedere Esecuzione asincrona (metodo di notifica).

Per impostazione predefinita, i driver eseguono funzioni ODBC in modo sincrono; ovvero, l'applicazione chiama una funzione e il driver non restituisce il controllo all'applicazione fino al termine dell'esecuzione della funzione. Tuttavia, alcune funzioni possono essere eseguite in modo asincrono; ovvero, l'applicazione chiama la funzione e il driver, dopo un'elaborazione minima, restituisce il controllo all'applicazione. L'applicazione può quindi chiamare altre funzioni mentre la prima funzione è ancora in esecuzione.

L'esecuzione asincrona è supportata per la maggior parte delle funzioni in gran parte eseguite nell'origine dati, ad esempio le funzioni per stabilire connessioni, preparare ed eseguire istruzioni SQL, recuperare metadati, recuperare dati e transazioni di commit. È particolarmente utile quando l'attività eseguita nell'origine dati richiede molto tempo, ad esempio un processo di accesso o una query complessa su un database di grandi dimensioni.

Quando l'applicazione esegue una funzione con un'istruzione o una connessione abilitata per l'elaborazione asincrona, il driver esegue una quantità minima di elaborazione, ad esempio il controllo degli argomenti per gli errori, passa l'elaborazione all'origine dati e restituisce il controllo all'applicazione con il codice di ritorno SQL_STILL_EXECUTING. L'applicazione esegue quindi altre attività. Per determinare quando la funzione asincrona è terminata, l'applicazione interroga il driver a intervalli regolari chiamando la funzione con gli stessi argomenti usati in origine. Se la funzione è ancora in esecuzione, restituisce SQL_STILL_EXECUTING; se l'esecuzione è stata completata, restituisce il codice restituito se fosse stato eseguito in modo sincrono, ad esempio SQL_SUCCESS, SQL_ERROR o SQL_NEED_DATA.

Se una funzione viene eseguita in modo sincrono o asincrono è specifica del driver. Si supponga, ad esempio, che i metadati del set di risultati vengano memorizzati nella cache nel driver. In questo caso, l'esecuzione di SQLDescribeCol richiede molto poco tempo e il driver deve semplicemente eseguire la funzione anziché ritardare artificialmente l'esecuzione. D'altra parte, se il driver deve recuperare i metadati dall'origine dati, deve restituire il controllo all'applicazione mentre esegue questa operazione. Pertanto, l'applicazione deve essere in grado di gestire un codice restituito diverso da SQL_STILL_EXECUTING quando esegue per la prima volta una funzione in modo asincrono.

Esecuzione asincrona di operazioni di istruzione

Le seguenti funzioni di dichiarazione operano su un'origine dati e sono eseguibili in modalità asincrona:

L'esecuzione asincrona dell'istruzione viene controllata per ogni istruzione o per ogni connessione, a seconda dell'origine dati. Ovvero, l'applicazione non specifica che una determinata funzione debba essere eseguita in modo asincrono, ma che qualsiasi funzione eseguita in una particolare istruzione debba essere eseguita in modo asincrono. Per scoprire quale è supportato, un'applicazione chiama SQLGetInfo con un'opzione di SQL_ASYNC_MODE. SQL_AM_CONNECTION viene restituito se l'esecuzione asincrona a livello di connessione (per un handle di istruzione) è supportata; SQL_AM_STATEMENT se è supportata l'esecuzione asincrona a livello di istruzione.

Per specificare che le funzioni eseguite con una determinata istruzione devono essere eseguite in modo asincrono, l'applicazione chiama SQLSetStmtAttr con l'attributo SQL_ATTR_ASYNC_ENABLE e lo imposta su SQL_ASYNC_ENABLE_ON. Se l'elaborazione asincrona a livello di connessione è supportata, l'attributo dell'istruzione SQL_ATTR_ASYNC_ENABLE è di sola lettura e il relativo valore corrisponde all'attributo di connessione della connessione in cui è stata allocata l'istruzione. È specifico del driver se il valore dell'attributo dell'istruzione viene impostato in fase di allocazione dell'istruzione o in un momento successivo. Il tentativo di impostarlo restituirà SQL_ERROR e SQLSTATE HYC00 (funzionalità facoltativa non implementata).

Per specificare che le funzioni eseguite con una determinata connessione devono essere eseguite in modo asincrono, l'applicazione chiama SQLSetConnectAttr con l'attributo SQL_ATTR_ASYNC_ENABLE e la imposta su SQL_ASYNC_ENABLE_ON. Tutti gli handle di istruzione futuri allocati nella connessione verranno abilitati per l'esecuzione asincrona; è definito dal driver se gli handle di istruzione esistenti verranno abilitati da questa azione. Se SQL_ATTR_ASYNC_ENABLE è impostato su SQL_ASYNC_ENABLE_OFF, tutte le istruzioni nella connessione sono in modalità sincrona. Viene restituito un errore se l'esecuzione asincrona è abilitata mentre è presente un'istruzione attiva nella connessione.

Per determinare il numero massimo di istruzioni simultanee attive in modalità asincrona che il driver può supportare in una determinata connessione, l'applicazione chiama SQLGetInfo con l'opzione SQL_MAX_ASYNC_CONCURRENT_STATEMENTS.

Il codice seguente illustra il funzionamento del modello di polling:

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.  

Mentre una funzione viene eseguita in modo asincrono, l'applicazione può chiamare funzioni in qualsiasi altra istruzione. L'applicazione può anche chiamare funzioni su qualsiasi connessione, ad eccezione di quella associata all'istruzione asincrona. L'applicazione può tuttavia chiamare solo la funzione originale e quelle successive (utilizzando l'handle di istruzione o l'handle della connessione associata, o l'handle di ambiente), dopo che un'operazione di istruzione restituisce SQL_STILL_EXECUTING.

Se l'applicazione chiama qualsiasi altra funzione con l'istruzione asincrona o con la connessione associata a tale istruzione, la funzione restituisce ad esempio SQLSTATE HY010 (errore di sequenza di funzione).

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 un'applicazione chiama una funzione per determinare se è ancora in esecuzione in modo asincrono, deve usare l'handle di istruzione originale. Ciò è dovuto al fatto che l'esecuzione asincrona viene rilevata in base alle istruzioni. L'applicazione deve inoltre fornire valori validi per gli altri argomenti, ovvero gli argomenti originali, per superare il controllo degli errori nel gestore dei driver. Tuttavia, dopo che il driver controlla l'handle di istruzione e determina che l'istruzione viene eseguita in modo asincrono, ignora tutti gli altri argomenti.

Mentre una funzione viene eseguita in modo asincrono, ovvero dopo aver restituito SQL_STILL_EXECUTING e prima che restituisca un codice diverso, l'applicazione può annullarla chiamando SQLCancel o SQLCancelHandle con lo stesso handle di istruzione. Non si garantisce che questa operazione annulli l'esecuzione della funzione. Ad esempio, la funzione potrebbe essere già stata completata. Inoltre, il codice restituito da SQLCancel o SQLCancelHandle indica solo se il tentativo di annullare la funzione è riuscito, non se ha effettivamente annullato la funzione. Per determinare se la funzione è stata annullata, l'applicazione chiama nuovamente la funzione. Se la funzione è stata annullata, restituisce SQL_ERROR e SQLSTATE HY008 (operazione annullata). Se la funzione non è stata annullata, restituisce un altro codice, ad esempio SQL_SUCCESS, SQL_STILL_EXECUTING o SQL_ERROR con un'istruzione SQLSTATE diversa.

Per disabilitare l'esecuzione asincrona di una determinata istruzione quando il driver supporta l'elaborazione asincrona a livello di istruzione, l'applicazione chiama SQLSetStmtAttr con l'attributo SQL_ATTR_ASYNC_ENABLE e lo imposta su SQL_ASYNC_ENABLE_OFF. Se il driver supporta l'elaborazione asincrona a livello di connessione, l'applicazione chiama SQLSetConnectAttr per impostare SQL_ATTR_ASYNC_ENABLE su SQL_ASYNC_ENABLE_OFF, che disabilita l'esecuzione asincrona di tutte le istruzioni nella connessione.

L'applicazione deve elaborare i record di diagnostica nel ciclo ripetuto della funzione originale. Se SQLGetDiagField o SQLGetDiagRec viene chiamato quando viene eseguita una funzione asincrona, restituirà l'elenco corrente di record di diagnostica. Ogni volta che viene ripetuta la chiamata originale della funzione, cancella i record di diagnostica precedenti.

Esecuzione asincrona di operazioni di connessione

Prima di ODBC 3.8, è stata consentita l'esecuzione asincrona per operazioni correlate all'istruzione, ad esempio preparare, eseguire e recuperare, nonché per le operazioni sui metadati del catalogo. A partire da ODBC 3.8, l'esecuzione asincrona è anche possibile per operazioni correlate alla connessione, ad esempio connessione, disconnessione, commit e rollback.

Per altre informazioni su ODBC 3.8, vedere Novità di ODBC 3.8.

L'esecuzione di operazioni di connessione in modo asincrono è utile negli scenari seguenti:

  • Quando un numero ridotto di thread gestisce un numero elevato di dispositivi con frequenze di dati molto elevate. Per ottimizzare la velocità di risposta e la scalabilità, è consigliabile che tutte le operazioni siano asincrone.

  • Quando si desidera sovrapporre le operazioni del database su più connessioni per ridurre i tempi di trasferimento trascorsi.

  • Chiamate ODBC asincrone efficienti e la possibilità di annullare le operazioni di connessione consentono a un'applicazione di annullare qualsiasi operazione lenta senza dover attendere timeout.

Le funzioni seguenti, che operano sugli handle di connessione, possono ora essere eseguite in modo asincrono:

Per determinare se un driver supporta operazioni asincrone su queste funzioni, un'applicazione chiama SQLGetInfo con SQL_ASYNC_DBC_FUNCTIONS. SQL_ASYNC_DBC_CAPABLE viene restituito se sono supportate operazioni asincrone. SQL_ASYNC_DBC_NOT_CAPABLE viene restituito se le operazioni asincrone non sono supportate.

Per specificare che le funzioni eseguite con una determinata connessione devono essere eseguite in modo asincrono, l'applicazione chiama SQLSetConnectAttr e imposta l'attributo SQL_ATTR_ASYNC_DBC_FUNCTIONS_ENABLE su SQL_ASYNC_DBC_ENABLE_ON. L'impostazione di un attributo di connessione prima di stabilire una connessione viene sempre eseguita in modo sincrono. Inoltre, l'operazione che imposta l'attributo di connessione SQL_ATTR_ASYNC_DBC_FUNCTIONS_ENABLE con SQLSetConnectAttr viene sempre eseguita in modo sincrono.

Un'applicazione può abilitare l'operazione asincrona prima di stabilire una connessione. Poiché Gestione driver non è in grado di determinare quale driver usare prima di stabilire una connessione, Gestione driver restituirà sempre l'esito positivo in SQLSetConnectAttr. Tuttavia, potrebbe non riuscire a connettersi se il driver ODBC non supporta operazioni asincrone.

In generale, può essere presente al massimo una funzione in esecuzione asincrona associata a un handle di connessione o a un handle di istruzione specifico. Tuttavia, un handle di connessione può avere più di un handle di istruzione associato. Se non è in esecuzione alcuna operazione asincrona nell'handle di connessione, un handle di istruzione associato può eseguire un'operazione asincrona. Analogamente, è possibile effettuare un'operazione asincrona su un handle di connessione se non sono in corso operazioni asincrone su alcun handle di istruzione associato. Un tentativo di eseguire un'operazione asincrona usando un handle che esegue attualmente un'operazione asincrona restituirà HY010, "Errore della sequenza di funzioni".

Se un'operazione di connessione restituisce SQL_STILL_EXECUTING, un'applicazione può chiamare solo la funzione originale e le funzioni seguenti per tale handle di connessione:

  • SQLCancelHandle (nell'handle di connessione)

  • SQLGetDiagField

  • Sqlgetdiagrec

  • SQLAllocHandle (allocazione ENV/DBC)

  • SQLAllocHandleStd (allocazione di ENV/DBC)

  • SQLGetEnvAttr

  • SQLGetConnectAttr

  • SQLDataSources

  • SQLDrivers

  • Sqlgetinfo

  • SQLGetFunctions

L'applicazione deve elaborare i record di diagnostica nel ciclo ripetuto della funzione originale. Se SQLGetDiagField o SQLGetDiagRec viene chiamato quando viene eseguita una funzione asincrona, restituirà l'elenco corrente di record di diagnostica. Ogni volta che si ripete l'invocazione della funzione originale, vengono cancellati i record di diagnostica precedenti.

Se una connessione viene aperta o chiusa in modo asincrono, l'operazione viene completata quando l'applicazione riceve SQL_SUCCESS o SQL_SUCCESS_WITH_INFO nella chiamata di funzione originale.

È stata aggiunta una nuova funzione a ODBC 3.8, SQLCancelHandle. Questa funzione annulla le sei funzioni di connessione (SQLBrowseConnect, SQLConnect, SQLDisconnect, SQLDriverConnect, SQLEndTran e SQLSetConnectAttr). Un'applicazione deve chiamare SQLGetFunctions per determinare se il driver supporta SQLCancelHandle. Come per SQLCancel, se SQLCancelHandle restituisce l'esito positivo, non significa che l'operazione sia stata annullata. Un'applicazione deve chiamare di nuovo la funzione originale per determinare se l'operazione è stata annullata. SQLCancelHandle consente di annullare operazioni asincrone sugli handle di connessione o sugli handle di istruzione. L'uso di SQLCancelHandle per annullare un'operazione su un handle di istruzione equivale a chiamare SQLCancel.

Non è necessario supportare contemporaneamente le operazioni di SQLCancelHandle e di connessione asincrona. Un driver può supportare operazioni di connessione asincrone, ma non SQLCancelHandle o viceversa.

Le operazioni di connessione asincrone e SQLCancelHandle possono essere usate anche dalle applicazioni ODBC 3.x e ODBC 2.x con un driver ODBC 3.8 e ODBC 3.8 Driver Manager. Per informazioni su come abilitare un'applicazione meno recente per l'uso di nuove funzionalità in una versione ODBC successiva, vedere Matrice di compatibilità.

Gestione del pool di connessioni

Ogni volta che il pool di connessioni è abilitato, le operazioni asincrone sono supportate solo al minimo per stabilire una connessione (con SQLConnect e SQLDriverConnect) e chiudere una connessione con SQLDisconnect. Tuttavia, un'applicazione deve comunque essere in grado di gestire il valore restituito SQL_STILL_EXECUTING da SQLConnect, SQLDriverConnect e SQLDisconnect.

Quando il pool di connessioni è abilitato, SQLEndTran e SQLSetConnectAttr sono supportati per le operazioni asincrone.

Esempi

A. Abilitare l'esecuzione asincrona delle funzioni di connessione

Nell'esempio seguente viene illustrato come usare SQLSetConnectAttr per abilitare l'esecuzione asincrona per le funzioni correlate alla connessione.

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. Operazioni di commit asincrone

Questo esempio mostra le operazioni di commit asincrone. Le operazioni di rollback possono essere eseguite anche in questo modo.

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

Vedere anche

Esecuzione di istruzioni ODBC