Dela via


Asynkron körning (avsökningsmetod)

Före ODBC 3.8 och Windows 7 SDK tilläts asynkrona åtgärder endast på instruktionsfunktioner. Mer information finns i Köra instruktionsåtgärder asynkront senare i det här avsnittet.

ODBC 3.8 i Windows 7 SDK introducerade asynkron körning på anslutningsrelaterade åtgärder. Mer information finns i avsnittet Kör anslutningsåtgärder asynkront senare i det här avsnittet.

I Windows 7-SDK:n, för asynkrona instruktions- eller anslutningsåtgärder, bestämde ett program att den asynkrona operationen slutfördes med hjälp av polling-metoden. Från och med Windows 8 SDK kan du fastställa att en asynkron åtgärd har slutförts med hjälp av meddelandemetoden. Mer information finns i Asynkron körning (notifikationsmetod).

Som standard kör drivrutiner ODBC-funktioner synkront. Det innebär att programmet anropar en funktion och drivrutinen returnerar inte kontrollen till programmet förrän den har slutfört körningen av funktionen. Vissa funktioner kan dock köras asynkront. Programmet anropar funktionen, och drivrutinen, efter minimal bearbetning, returnerar kontrollen till programmet. Programmet kan sedan anropa andra funktioner medan den första funktionen fortfarande körs.

Asynkron körning stöds för de flesta funktioner som till stor del körs på datakällan, till exempel funktioner för att upprätta anslutningar, förbereda och köra SQL-instruktioner, hämta metadata, hämta data och checka in transaktioner. Det är mest användbart när uppgiften som körs på datakällan tar lång tid, till exempel en inloggningsprocess eller en komplex fråga mot en stor databas.

När programmet kör en funktion med en instruktion eller anslutning som är aktiverad för asynkron bearbetning utför drivrutinen minimalt med bearbetning (till exempel kontrollerar argument för fel), överlämnar bearbetningen till datakällan och returnerar kontroll till programmet med returkoden SQL_STILL_EXECUTING. Programmet utför sedan andra uppgifter. För att avgöra när den asynkrona funktionen har slutförts avsöker programmet drivrutinen med jämna mellanrum genom att anropa funktionen med samma argument som den ursprungligen använde. Om funktionen fortfarande körs returneras SQL_STILL_EXECUTING. Om körningen är klar returnerar den koden som den skulle ha returnerat om den hade körts synkront, till exempel SQL_SUCCESS, SQL_ERROR eller SQL_NEED_DATA.

Om en funktion körs synkront eller asynkront är drivrutinsspecifikt. Anta till exempel att resultatuppsättningens metadata cachelagras i drivrutinen. I det här fallet tar det väldigt liten tid att köra SQLDescribeCol och drivrutinen bör helt enkelt utföra funktionen i stället för att fördröja körningen artificiellt. Å andra sidan, om drivrutinen behöver hämta metadata från datakällan, bör den returnera kontrollen till programmet medan den gör detta. Därför måste programmet kunna hantera en annan returkod än SQL_STILL_EXECUTING när den först kör en funktion asynkront.

Köra instruktionsåtgärder asynkront

Följande instruktionsfunktioner fungerar på en datakälla och kan köras asynkront:

Asynkron instruktionskörning kan styras antingen per instruktion eller per anslutning, beroende på datakällan. Det innebär att programmet inte anger att en viss funktion ska köras asynkront, utan att alla funktioner som körs på en viss instruktion ska köras asynkront. För att ta reda på vilken som stöds anropar ett program SQLGetInfo med alternativet SQL_ASYNC_MODE. SQL_AM_CONNECTION returneras om asynkron körning på anslutningsnivå (för ett instruktionshandtag) stöds. SQL_AM_STATEMENT om asynkron körning på instruktionsnivå stöds.

För att ange att funktioner som körs med en viss instruktion ska köras asynkront anropar programmet SQLSetStmtAttr med attributet SQL_ATTR_ASYNC_ENABLE och anger det till SQL_ASYNC_ENABLE_ON. Om asynkron bearbetning på anslutningsnivå stöds är SQL_ATTR_ASYNC_ENABLE-instruktionsattributet skrivskyddat och dess värde är detsamma som anslutningsattributet för anslutningen som -instruktionen allokerades till. Det är drivrutinsspecifikt om värdet för instruktionsattributet anges vid instruktionsallokeringstid eller senare. Om du försöker ange den returneras SQL_ERROR och SQLSTATE HYC00 (valfri funktion implementeras inte).

För att ange att funktioner som körs med en viss anslutning ska köras asynkront anropar programmet SQLSetConnectAttr med attributet SQL_ATTR_ASYNC_ENABLE och anger det till SQL_ASYNC_ENABLE_ON. Alla framtida frågehanterare som allokeras på anslutningen aktiveras för asynkron körning. Det är drivrutinsdefinierat om befintliga frågehanterare aktiveras genom denna åtgärd. Om SQL_ATTR_ASYNC_ENABLE är inställt på SQL_ASYNC_ENABLE_OFF är alla instruktioner för anslutningen i synkront läge. Ett fel returneras om asynkron körning är aktiverad medan det finns en aktiv instruktion för anslutningen.

För att fastställa det maximala antalet aktiva samtidiga instruktioner i asynkront läge som drivrutinen kan stödja på en viss anslutning anropar programmet SQLGetInfo med alternativet SQL_MAX_ASYNC_CONCURRENT_STATEMENTS.

Följande kod visar hur avsökningsmodellen fungerar:

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.  

Medan en funktion körs asynkront kan programmet anropa funktioner på andra instruktioner. Programmet kan också anropa funktioner på alla anslutningar, förutom den som är associerad med den asynkrona instruktionen. Men programmet kan bara anropa den ursprungliga funktionen och följande funktioner (med instruktionshandtaget eller dess associerade anslutning, miljöhandtaget) efter att en instruktionsåtgärd returnerar SQL_STILL_EXECUTING:

Om programmet anropar någon annan funktion med den asynkrona instruktionen eller med anslutningen som är associerad med instruktionen returnerar funktionen TILL exempel SQLSTATE HY010 (funktionssekvensfel).

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  
}  

När en applikation anropar en funktion för att avgöra om den fortfarande körs asynkront måste den använda det ursprungliga instruktionshandtaget. Det beror på att asynkron körning spåras per instruktion. Programmet måste också ange giltiga värden för de andra argumenten – de ursprungliga argumenten räcker – för att klara felkontrollen i Drivrutinshanteraren. Men efter att drivrutinen har kontrollerat instruktionshandtaget och fastställt att instruktionen körs asynkront, ignorerar den alla andra argument.

Medan en funktion körs asynkront – det vill säga när den har returnerat SQL_STILL_EXECUTING och innan den returnerar en annan kod – kan programmet avbryta den genom att anropa SQLCancel eller SQLCancelHandle med samma instruktionshandtag. Detta är inte garanterat att avbryta funktionskörningen. Funktionen kan till exempel redan ha slutförts. Dessutom anger koden som returneras av SQLCancel eller SQLCancelHandle endast om försöket att avbryta funktionen lyckades, inte om den faktiskt avbröt funktionen. För att avgöra om funktionen avbröts anropar programmet funktionen igen. Om funktionen avbröts returneras SQL_ERROR och SQLSTATE HY008 (åtgärden avbröts). Om funktionen inte avbröts returneras en annan kod, till exempel SQL_SUCCESS, SQL_STILL_EXECUTING eller SQL_ERROR med en annan SQLSTATE.

Om du vill inaktivera asynkron körning av en viss instruktion när drivrutinen stöder asynkron bearbetning på instruktionsnivå anropar programmet SQLSetStmtAttr med attributet SQL_ATTR_ASYNC_ENABLE och anger det till SQL_ASYNC_ENABLE_OFF. Om drivrutinen stöder asynkron bearbetning på anslutningsnivå anropar programmet SQLSetConnectAttr för att ange SQL_ATTR_ASYNC_ENABLE till SQL_ASYNC_ENABLE_OFF, vilket inaktiverar asynkron körning av alla instruktioner på anslutningen.

I den ursprungliga funktionen bör programmet bearbeta diagnostikposter/dataloggar i den återkommande loopen. Om SQLGetDiagField eller SQLGetDiagRec anropas när en asynkron funktion körs returneras den aktuella listan över diagnostikposter. Varje gång det ursprungliga funktionsanropet upprepas raderas tidigare diagnostikposter.

Köra anslutningsåtgärder asynkront

Före ODBC 3.8 tilläts asynkron körning för instruktionsrelaterade åtgärder som förberedelse, körning och hämtning samt för katalogmetadataåtgärder. Från och med ODBC 3.8 är asynkron körning också möjlig för anslutningsrelaterade åtgärder som anslutning, frånkoppling, incheckning och återställning.

Mer information om ODBC 3.8 finns i Nyheter i ODBC 3.8.

Att köra anslutningsåtgärder asynkront är användbart i följande scenarier:

  • När ett litet antal trådar hanterar ett stort antal enheter med mycket höga datahastigheter. För att maximera svarstiden och skalbarheten är det önskvärt att alla åtgärder är asynkrona.

  • När du vill överlappa databasåtgärder över flera anslutningar för att minska förflutna överföringstider.

  • Med effektiva asynkrona ODBC-anrop och möjligheten att avbryta anslutningsåtgärder kan ett program avbryta eventuella långsamma åtgärder utan att behöva vänta på tidsgränser.

Följande funktioner, som fungerar på anslutningshandtag, kan nu köras asynkront:

För att avgöra om en drivrutin stöder asynkrona åtgärder på dessa funktioner anropar ett program SQLGetInfo med SQL_ASYNC_DBC_FUNCTIONS. SQL_ASYNC_DBC_CAPABLE returneras om asynkrona åtgärder stöds. SQL_ASYNC_DBC_NOT_CAPABLE returneras om asynkrona åtgärder inte stöds.

För att ange att funktioner som körs med en viss anslutning ska köras asynkront anropar programmet SQLSetConnectAttr och anger attributet SQL_ATTR_ASYNC_DBC_FUNCTIONS_ENABLE till SQL_ASYNC_DBC_ENABLE_ON. Att ange ett anslutningsattribut innan du upprättar en anslutning körs alltid synkront. Dessutom körs alltid åtgärdsinställningen för anslutningsattributet SQL_ATTR_ASYNC_DBC_FUNCTIONS_ENABLE med SQLSetConnectAttr synkront.

Ett program kan aktivera asynkron åtgärd innan en anslutning upprättas. Eftersom Driver Manager inte kan avgöra vilken drivrutin som ska användas innan du upprättar en anslutning returnerar Driver Manager alltid framgång i SQLSetConnectAttr. Det kan dock misslyckas med att ansluta om ODBC-drivrutinen inte stöder asynkrona åtgärder.

I allmänhet kan det finnas högst en funktion som exekveras asynkront som är associerad med en viss anslutningsreferens eller uttryckshandtag. En anslutningsreferens kan dock ha mer än en associerad instruktionsreferens. Om det inte körs någon asynkron åtgärd på anslutningshandtaget kan ett associerat kommandohandtag starta en asynkron åtgärd. På samma sätt kan du ha en asynkron åtgärd på en anslutningsreferens om det inte pågår några asynkrona åtgärder på någon associerad instruktionsreferens. Ett försök att köra en asynkron åtgärd med hjälp av ett handtag som för närvarande kör en asynkron åtgärd returnerar HY010, "Funktionssekvensfel".

Om en anslutningsåtgärd returnerar SQL_STILL_EXECUTING kan ett program bara anropa den ursprungliga funktionen och följande funktioner för anslutningshandtaget:

  • SQLCancelHandle (på anslutningshandtaget)

  • SQLGetDiagField

  • SQLGetDiagRec

  • SQLAllocHandle (allokera ENV/DBC)

  • SQLAllocHandleStd (allokera ENV/DBC)

  • SQLGetEnvAttr

  • SQLGetConnectAttr

  • SQLDataSources

  • SQLDrivers

  • SQLGetInfo

  • SQLGetFunctions

Programmet bör bearbeta diagnosposter i den återkommande loopen i den ursprungliga funktionen. Om SQLGetDiagField eller SQLGetDiagRec anropas när en asynkron funktion körs returneras den aktuella listan över diagnostikposter. Varje gång det ursprungliga funktionsanropet upprepas rensar det tidigare diagnostikposter.

Om en anslutning öppnas eller stängs asynkront slutförs åtgärden när programmet tar emot SQL_SUCCESS eller SQL_SUCCESS_WITH_INFO i det ursprungliga funktionsanropet.

En ny funktion har lagts till i ODBC 3.8, SQLCancelHandle. Den här funktionen avbryter de sex anslutningsfunktionerna (SQLBrowseConnect, SQLConnect, SQLDisconnect, SQLDriverConnect, SQLEndTran och SQLSetConnectAttr). Ett program bör anropa SQLGetFunctions för att avgöra om drivrutinen stöder SQLCancelHandle. Precis som med SQLCancel innebär det inte att åtgärden avbröts om SQLCancelHandle returnerar framgång. Ett program bör anropa den ursprungliga funktionen igen för att avgöra om åtgärden avbröts. Med SQLCancelHandle kan du avbryta asynkrona åtgärder på anslutningshandtag eller instruktionshandtag. Att använda SQLCancelHandle för att avbryta en åtgärd på ett instruktionshandtag är detsamma som att anropa SQLCancel.

Det är inte nödvändigt att stödja både SQLCancelHandle och asynkrona anslutningsåtgärder samtidigt. En drivrutin kan stödja asynkrona anslutningsåtgärder, men inte SQLCancelHandle eller vice versa.

Asynkrona anslutningsåtgärder och SQLCancelHandle kan också användas av ODBC 3.x- och ODBC 2.x-program med en ODBC 3.8-drivrutin och ODBC 3.8 Driver Manager. Information om hur du aktiverar ett äldre program för att använda nya funktioner i senare ODBC-version finns i Kompatibilitetsmatris.

Anslutningspoolning

När anslutningspooler är aktiverade stöds asynkrona åtgärder endast minimalt för att upprätta en anslutning (med SQLConnect och SQLDriverConnect) och stänga en anslutning med SQLDisconnect. Men en applikation bör fortfarande kunna hantera SQL_STILL_EXECUTING returneringsvärdet från SQLConnect, SQLDriverConnect och SQLDisconnect.

När anslutningspooler är aktiverade stöds SQLEndTran och SQLSetConnectAttr för asynkrona åtgärder.

Examples

A. Aktivera asynkron körning av anslutningsfunktioner

I följande exempel visas hur du använder SQLSetConnectAttr för att aktivera asynkron körning för anslutningsrelaterade funktioner.

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. Asynkrona incheckningsåtgärder

Det här exemplet visar asynkrona commit-operationer. Återställningsåtgärder kan också utföras på det här sättet.

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

Se även

Exekvera kommandon ODBC