비동기 실행(폴링 메서드)
ODBC 3.8 및 Windows 7 SDK 이전에는 문 함수에서만 비동기 작업이 허용되었습니다. 자세한 내용은 이 항목의 뒷부분에 있는 문 실행 작업을 비동기적으로 참조하세요.
Windows 7 SDK의 ODBC 3.8에는 연결 관련 작업에 대한 비동기 실행이 도입되었습니다. 자세한 내용은 이 항목의 뒷부분에 있는 커넥트ion Operations Asynchronously 실행 섹션을 참조하세요.
Windows 7 SDK에서 비동기 문 또는 연결 작업의 경우 애플리케이션은 폴링 방법을 사용하여 비동기 작업이 완료되었음을 확인했습니다. Windows 8 SDK부터 알림 방법을 사용하여 비동기 작업이 완료되었는지 확인할 수 있습니다. 자세한 내용은 비동기 실행(알림 방법)을 참조하세요.
기본적으로 드라이버는 ODBC 함수를 동기적으로 실행합니다. 즉, 애플리케이션이 함수를 호출하고 드라이버가 함수 실행을 완료할 때까지 애플리케이션에 컨트롤을 반환하지 않습니다. 그러나 일부 함수는 비동기적으로 실행할 수 있습니다. 즉, 애플리케이션은 함수를 호출하고 드라이버는 최소한의 처리 후 애플리케이션에 컨트롤을 반환합니다. 그러면 첫 번째 함수가 계속 실행되는 동안 애플리케이션에서 다른 함수를 호출할 수 있습니다.
비동기 실행은 연결을 설정하고, SQL 문을 준비 및 실행하고, 메타데이터를 검색하고, 데이터를 가져오고, 트랜잭션을 커밋하는 함수와 같이 데이터 원본에서 주로 실행되는 대부분의 함수에 대해 지원됩니다. 데이터 원본에서 실행되는 작업이 로그인 프로세스 또는 대규모 데이터베이스에 대한 복잡한 쿼리와 같은 시간이 오래 걸리는 경우에 가장 유용합니다.
애플리케이션이 비동기 처리에 사용할 수 있는 문 또는 연결이 있는 함수를 실행하는 경우 드라이버는 최소한의 처리(예: 오류에 대한 인수 검사), 데이터 원본에 대한 손 처리를 수행하고, SQL_STILL_EXECUTING 반환 코드를 사용하여 컨트롤을 애플리케이션에 반환합니다. 그런 다음 애플리케이션은 다른 작업을 수행합니다. 비동기 함수가 완료된 시기를 확인하기 위해 애플리케이션은 원래 사용된 것과 동일한 인수를 사용하여 함수를 호출하여 정기적으로 드라이버를 폴링합니다. 함수가 계속 실행 중이면 SQL_STILL_EXECUTING; 실행이 완료되면 SQL_SUCCESS, SQL_ERROR 또는 SQL_NEED_DATA 같이 동기적으로 실행했을 때 반환했을 코드를 반환합니다.
함수가 동기적으로 또는 비동기적으로 실행되는지 여부는 드라이버에 따라 다릅니다. 예를 들어 결과 집합 메타데이터가 드라이버에 캐시된다고 가정합니다. 이 경우 SQLDescribeCol을 실행하는 데 시간이 거의 걸리지 않으며 드라이버는 인위적으로 실행을 지연하는 대신 함수를 실행해야 합니다. 반면, 드라이버가 데이터 원본에서 메타데이터를 검색해야 하는 경우 이 작업을 수행하는 동안 애플리케이션에 제어권을 반환해야 합니다. 따라서 애플리케이션은 함수를 처음 비동기적으로 실행할 때 SQL_STILL_EXECUTING 이외의 반환 코드를 처리할 수 있어야 합니다.
문 연산을 비동기적으로 실행
다음 문 함수는 데이터 원본에서 작동하며 비동기적으로 실행할 수 있습니다.
SQLBulkOperations
SQLColAttribute
SQLColumnPrivileges
SQLColumns
SQLDescribeCol
SQLDescribeParam
SQLExecDirect
SQLExecute
SQLFetch
비동기 문 실행은 데이터 원본에 따라 문별 또는 연결별로 제어됩니다. 즉, 애플리케이션은 특정 함수를 비동기적으로 실행할 것이 아니라 특정 문에서 실행되는 모든 함수를 비동기적으로 실행하도록 지정합니다. 지원되는 항목을 찾기 위해 애플리케이션은 SQL_ASYNC_MODE 옵션을 사용하여 SQLGetInfo를 호출합니다. 문 핸들에 대한 연결 수준 비동기 실행이 지원되면 SQL_AM_CONNECTION 반환됩니다. 문 수준 비동기 실행이 지원되는지 SQL_AM_STATEMENT.
특정 문으로 실행된 함수를 비동기적으로 실행하도록 지정하기 위해 애플리케이션은 SQL_ATTR_ASYNC_ENABLE 특성을 사용하여 SQLSetStmtAttr을 호출하고 SQL_ASYNC_ENABLE_ON 설정합니다. 연결 수준 비동기 처리가 지원되는 경우 SQL_ATTR_ASYNC_ENABLE 문 특성은 읽기 전용이며 해당 값은 문이 할당된 연결의 연결 특성과 동일합니다. 문 특성의 값이 문 할당 시간 이상에서 설정되는지 여부에 따라 드라이버별로 다릅니다. 설정을 시도하면 SQL_ERROR 및 SQLSTATE HYC00(선택적 기능이 구현되지 않음)이 반환됩니다.
특정 연결로 실행되는 함수를 비동기적으로 실행하도록 지정하기 위해 애플리케이션은 SQL_ATTR_ASYNC_ENABLE 특성을 사용하여 SQLSet커넥트Attr을 호출하고 SQL_ASYNC_ENABLE_ON 설정합니다. 연결에 할당된 모든 이후 문 핸들은 비동기 실행에 대해 사용하도록 설정됩니다. 이 작업을 통해 기존 문 핸들을 사용할지 여부는 드라이버에서 정의됩니다. SQL_ATTR_ASYNC_ENABLE SQL_ASYNC_ENABLE_OFF 설정되면 연결의 모든 문이 동기 모드로 설정됩니다. 연결에 활성 문이 있는 동안 비동기 실행을 사용하도록 설정하면 오류가 반환됩니다.
드라이버가 지정된 연결에서 지원할 수 있는 비동기 모드에서 활성 동시 문의 최대 수를 확인하려면 애플리케이션은 SQL_MAX_ASYNC_CONCURRENT_STATEMENTS 옵션을 사용하여 SQLGetInfo를 호출합니다.
다음 코드는 폴링 모델의 작동 방식을 보여 줍니다.
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.
함수가 비동기적으로 실행되는 동안 애플리케이션은 다른 문에서 함수를 호출할 수 있습니다. 애플리케이션은 비동기 문과 연결된 함수를 제외하고 모든 연결에서 함수를 호출할 수도 있습니다. 그러나 문 작업이 SQL_STILL_EXECUTING 반환한 후에 애플리케이션은 문 핸들 또는 연결된 연결, 환경 핸들을 사용하여 원래 함수와 다음 함수만 호출할 수 있습니다.
SQLCancelHandle (문 핸들에서)
애플리케이션이 비동기 문 또는 해당 문과 연결된 연결을 사용하여 다른 함수를 호출하는 경우 함수는 SQLSTATE HY010(함수 시퀀스 오류)을 반환합니다.
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
}
애플리케이션이 함수를 호출하여 비동기적으로 실행 중인지 여부를 확인하는 경우 원래 문 핸들을 사용해야 합니다. 비동기 실행은 문별로 추적되기 때문입니다. 또한 애플리케이션은 드라이버 관리자에서 과거 오류 검사 가져오기 위해 원래 인수가 수행하는 다른 인수에 유효한 값을 제공해야 합니다. 그러나 드라이버가 문 핸들을 검사 문이 비동기적으로 실행되는지 확인한 후에는 다른 모든 인수를 무시합니다.
함수가 비동기적으로 실행되는 동안( 즉, SQL_STILL_EXECUTING 반환한 후 다른 코드를 반환하기 전에) 애플리케이션은 동일한 문 핸들을 사용하여 SQLCancel 또는 SQLCancelHandle을 호출하여 이를 취소할 수 있습니다. 이는 함수 실행을 취소하도록 보장되지 않습니다. 예를 들어 함수가 이미 완료되었을 수 있습니다. 또한 SQLCancel 또는 SQLCancelHandle에서 반환된 코드는 함수를 실제로 취소했는지 여부가 아니라 함수를 취소하려는 시도가 성공했는지 여부만 나타냅니다. 함수가 취소되었는지 여부를 확인하기 위해 애플리케이션은 함수를 다시 호출합니다. 함수가 취소된 경우 SQL_ERROR 및 SQLSTATE HY008(작업이 취소됨)을 반환합니다. 함수가 취소되지 않은 경우 다른 SQLSTATE를 사용하여 SQL_SUCCESS, SQL_STILL_EXECUTING 또는 SQL_ERROR 같은 다른 코드를 반환합니다.
드라이버가 문 수준 비동기 처리를 지원할 때 특정 문의 비동기 실행을 사용하지 않도록 설정하기 위해 애플리케이션은 SQL_ATTR_ASYNC_ENABLE 특성을 사용하여 SQLSetStmtAttr을 호출하고 SQL_ASYNC_ENABLE_OFF 설정합니다. 드라이버가 연결 수준 비동기 처리를 지원하는 경우 애플리케이션은 SQLSet커넥트Attr을 호출하여 SQL_ATTR_ASYNC_ENABLE SQL_ASYNC_ENABLE_OFF 설정하여 연결에서 모든 문의 비동기 실행을 사용하지 않도록 설정합니다.
애플리케이션은 원래 함수의 반복 루프에서 진단 레코드를 처리해야 합니다. 비동기 함수를 실행할 때 SQLGetDiagField 또는 SQLGetDiagRec가 호출되면 현재 진단 레코드 목록이 반환됩니다. 원래 함수 호출이 반복되면 이전 진단 레코드가 지워집니다.
비동기적으로 커넥트ion 작업 실행
ODBC 3.8 이전에는 카탈로그 메타데이터 작업뿐만 아니라 준비, 실행 및 가져오기와 같은 문 관련 작업에 비동기 실행이 허용되었습니다. ODBC 3.8부터 연결, 연결 끊기, 커밋 및 롤백과 같은 연결 관련 작업에도 비동기 실행이 가능합니다.
ODBC 3.8에 대한 자세한 내용은 ODBC 3.8의 새로운 기능
연결 작업을 비동기적으로 실행하는 것은 다음 시나리오에서 유용합니다.
적은 수의 스레드가 데이터 속도가 매우 높은 많은 디바이스를 관리하는 경우 응답성과 확장성을 최대화하려면 모든 작업을 비동기화하는 것이 좋습니다.
경과된 전송 시간을 줄이기 위해 여러 연결을 통해 데이터베이스 작업을 겹치려는 경우.
효율적인 비동기 ODBC 호출 및 연결 작업을 취소하는 기능을 사용하면 사용자가 시간 제한을 기다리지 않고도 느린 작업을 취소할 수 있습니다.
이제 연결 핸들에서 작동하는 다음 함수를 비동기적으로 실행할 수 있습니다.
드라이버가 이러한 함수에 대한 비동기 작업을 지원하는지 여부를 확인하기 위해 애플리케이션은 SQL_ASYNC_DBC_FUNCTIONS 사용하여 SQLGetInfo를 호출합니다. 비동기 작업이 지원되는 경우 SQL_ASYNC_DBC_CAPABLE 반환됩니다. 비동기 작업이 지원되지 않는 경우 SQL_ASYNC_DBC_NOT_CAPABLE 반환됩니다.
특정 연결로 실행되는 함수를 비동기적으로 실행하도록 지정하기 위해 애플리케이션은 SQLSet커넥트Attr을 호출하고 SQL_ATTR_ASYNC_DBC_FUNCTIONS_ENABLE 특성을 SQL_ASYNC_DBC_ENABLE_ON 설정합니다. 연결을 설정하기 전에 연결 특성을 설정하면 항상 동기적으로 실행됩니다. 또한 연결 특성을 SQLSet커넥트Attr로 SQL_ATTR_ASYNC_DBC_FUNCTIONS_ENABLE 작업 설정은 항상 동기적으로 실행됩니다.
애플리케이션은 연결하기 전에 비동기 작업을 사용하도록 설정할 수 있습니다. 드라이버 관리자는 연결을 만들기 전에 사용할 드라이버를 결정할 수 없으므로 드라이버 관리자는 항상 SQLSet커넥트Attr에서 성공을 반환합니다. 그러나 ODBC 드라이버가 비동기 작업을 지원하지 않는 경우 연결에 실패할 수 있습니다.
일반적으로 특정 연결 핸들 또는 문 핸들과 연결된 최대 하나의 비동기 실행 함수가 있을 수 있습니다. 그러나 연결 핸들에는 둘 이상의 연결된 문 핸들이 있을 수 있습니다. 연결 핸들에서 실행되는 비동기 작업이 없는 경우 연결된 문 핸들은 비동기 작업을 실행할 수 있습니다. 마찬가지로 연결된 문 핸들에서 진행 중인 비동기 작업이 없는 경우 연결 핸들에 비동기 작업을 수행할 수 있습니다. 현재 비동기 작업을 실행하는 핸들을 사용하여 비동기 작업을 실행하려고 하면 HY010 "함수 시퀀스 오류"가 반환됩니다.
연결 작업이 SQL_STILL_EXECUTING 반환하는 경우 애플리케이션은 원래 함수와 해당 연결 핸들에 대해 다음 함수만 호출할 수 있습니다.
SQLCancelHandle (연결 핸들)
SQLGetDiagField
SQLGetDiagRec
SQLAllocHandle (ENV/DBC 할당)
SQLAllocHandleStd (ENV/DBC 할당)
SQLGetEnvAttr
SQLGet커넥트Attr
SQLDataSources
SQLDrivers
Sqlgetinfo
SQLGetFunctions
애플리케이션은 원래 함수의 반복 루프에서 진단 레코드를 처리해야 합니다. 비동기 함수를 실행할 때 SQLGetDiagField 또는 SQLGetDiagRec가 호출되면 현재 진단 레코드 목록이 반환됩니다. 원래 함수 호출이 반복되면 이전 진단 레코드가 지워집니다.
연결을 비동기적으로 열거나 닫는 경우 애플리케이션이 원래 함수 호출에서 SQL_SUCCESS 또는 SQL_SUCCESS_WITH_INFO 받으면 작업이 완료됩니다.
ODBC 3.8 SQLCancelHandle에 새 함수가 추가되었습니다. 이 함수는 6개의 연결 함수(SQLBrowse커넥트, SQL커넥트, SQLDisconnect, SQLDriver커넥트, SQLEndTran 및 SQLSet커넥트Attr)를 취소합니다. 애플리케이션은 SQLGetFunctions를 호출하여 드라이버가 SQLCancelHandle을 지원하는지 확인해야 합니다. SQLCancel과 마찬가지로 SQLCancelHandle이 성공을 반환하는 경우 작업이 취소되었음을 의미하지는 않습니다. 애플리케이션은 원래 함수를 다시 호출하여 작업이 취소되었는지 확인해야 합니다. SQLCancelHandle 을 사용하면 연결 핸들 또는 문 핸들에 대한 비동기 작업을 취소할 수 있습니다. SQLCancelHandle을 사용하여 문 핸들에 대한 작업을 취소하는 것은 SQLCancel을 호출하는 것과 같습니다.
SQLCancelHandle 및 비동기 연결 작업을 동시에 지원할 필요는 없습니다. 드라이버는 비동기 연결 작업을 지원할 수 있지만 SQLCancelHandle은 지원하지 않거나 그 반대의 경우도 마찬가지입니다.
비동기 연결 작업 및 SQLCancelHandle 은 ODBC 3.8 드라이버 및 ODBC 3.8 드라이버 관리자가 있는 ODBC 3.x 및 ODBC 2.x 애플리케이션에서도 사용할 수 있습니다. 이전 애플리케이션이 이후 ODBC 버전에서 새 기능을 사용하도록 설정하는 방법에 대한 자세한 내용은 호환성 매트릭스를 참조 하세요.
연결 풀링
연결 풀링을 사용하도록 설정할 때마다 비동기 작업은 연결 설정(SQL커넥트 및 SQLDriver커넥트 사용)을 설정하고 SQLDisconnect와의 연결을 닫는 경우에만 최소로 지원됩니다. 그러나 애플리케이션은 SQL커넥트, SQLDriver커넥트 및 SQLDisconnect에서 SQL_STILL_EXECUTING 반환 값을 처리할 수 있어야 합니다.
연결 풀링을 사용하도록 설정하면 SQLEndTran 및 SQLSet커넥트Attr이 비동기 작업에 대해 지원됩니다.
예제
A. 연결 함수의 비동기 실행 사용
다음 예제에서는 SQLSet커넥트Attr을 사용하여 연결 관련 함수에 대해 비동기 실행을 사용하도록 설정하는 방법을 보여 줍니다.
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. 비동기 커밋 작업
이 예제에서는 비동기 커밋 작업을 보여 줍니다. 이러한 방식으로 롤백 작업을 수행할 수도 있습니다.
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;
}