Esecuzione asincrona (metodo di polling)

Prima di ODBC 3.8 e dell’SDK Windows 7, 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 nell’SDK Windows 7 ha introdotto l'esecuzione asincrona nelle operazioni relative alla connessione. Per altre informazioni, vedere la sezione Esecuzione asincrona di operazioni di connessione più avanti in questo argomento.

Nell’SDK Windows 7, per le operazioni asincrone di istruzione o connessione, un'applicazione ha determinato che l'operazione asincrona è stata completata usando il metodo di polling. A partire dall’SDK Windows 8, è 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 ed eseguire il commit di transazioni. È 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 verificare gli errori), passa l'elaborazione all'origine dati e restituisce il controllo all'applicazione con il codice restituito SQL_STILL_EXECUTING. L’applicazione esegue quindi altre attività. Per determinare quando la funzione asincrona ha terminato, l'applicazione esegue il polling del 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 che avrebbe restituito se fosse stata eseguita in modo sincrono, ad esempio SQL_SUCCESS, SQL_ERROR o SQL_NEED_DATA.

L’esecuzione sincrona o asincrona di una funzione è 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 funzioni di istruzione seguenti operano su un'origine dati e possono essere eseguite in modo asincrono:

L'esecuzione asincrona dell'istruzione viene controllata per ogni istruzione o per ogni connessione, a seconda dell'origine dati. Ovvero, l'applicazione specifica che una determinata funzione deve essere eseguita in modo asincrono, ma che qualsiasi funzione eseguita in una determinata istruzione deve essere eseguita in modo asincrono. Per scoprire quale è supportata, 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 il fatto che il valore dell'attributo dell'istruzione venga impostato in fase di allocazione delle istruzioni o in seguito. 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 lo imposta su SQL_ASYNC_ENABLE_ON. Tutti gli handle di istruzione futuri allocati nella connessione verranno abilitati per l'esecuzione asincrona; è definito dal driver il fatto che gli handle di istruzione esistenti vengano 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ò chiamare funzioni anche su qualsiasi connessione, ad eccezione di quella associata all'istruzione asincrona. Tuttavia, l'applicazione può chiamare solo la funzione originale e le funzioni seguenti (con l'handle di istruzione o la connessione associata, 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 della 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 ottenere il controllo degli errori precedenti in Gestione 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 di restituire un codice diverso, l'applicazione può annullarla chiamando SQLCancel o SQLCancelHandle con lo stesso handle di istruzione. Questo non garantisce che l'esecuzione della funzione venga annullata. 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 SQLSTATE diverso.

Per disabilitare l'esecuzione asincrona di una particolare 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 dei record di diagnostica. Ogni volta che viene ripetuta la chiamata di funzione originale, questa cancella i record di diagnostica precedenti.

Esecuzione asincrona di operazioni di connessione

Prima di ODBC 3.8, era 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 è possibile anche 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 velocità di trasmissione 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.

  • Le efficienti chiamate ODBC asincrone e la possibilità di annullare le operazioni di connessione fanno sì che l'applicazione consenta all’utente di annullare qualsiasi operazione lenta senza dover attendere i timeout.

Le funzioni seguenti, che operano sugli handle di connessione, ora possono 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 non sono supportate operazioni asincrone.

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, può esserci un'operazione asincrona su un handle di connessione se non sono in corso operazioni asincrone su qualsiasi handle di istruzione associato. Il tentativo di eseguire un'operazione asincrona usando un handle che sta eseguendo un'operazione asincrona restituirà HY010, "Errore sequenza delle 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 di 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 dei record di diagnostica. Ogni volta che viene ripetuta la chiamata di funzione originale, questa cancella 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 SQLCancelHandle e di connessione asincrone. 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 Gestione driver ODBC 3.8. Per informazioni su come abilitare un'applicazione meno recente all'uso di nuove funzionalità in una versione ODBC successiva, vedere Matrice di compatibilità.

Pool di connessioni

Ogni volta che il pool di connessioni è abilitato, le operazioni asincrone sono supportate solo in modo 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 SQL_STILL_EXECUTING restituito da SQLConnect, SQLDriverConnect e SQLDisconnect.

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

Esempi

R. Abilitare l'esecuzione asincrona delle funzioni di connessione

Nell'esempio seguente viene illustrato come usare SQLSetConnectAttr per abilitare l'esecuzione asincrona per le funzioni relative 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. Anche le operazioni di rollback possono essere eseguite 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;  
}  

Vedi anche

Esecuzione di istruzioni ODBC