SQL Server Native Client에서 비동기 작업 수행

적용 대상:SQL ServerAzure SQL DatabaseAzure SQL Managed InstanceAzure Synapse AnalyticsAnalytics Platform System(PDW)

Important

SQL Server Native Client(약칭 SNAC)는 SQL Server 2022(16.x) 및 SSMS(SQL Server Management Studio) 19에서 제거되었습니다. SQL Server Native Client(SQLNCLI 또는 SQLNCLI11)와 레거시 Microsoft OLE DB Provider for SQL Server(SQLOLEDB)는 새로운 애플리케이션 개발에 권장되지 않습니다. 앞으로 새 SQL Server용 Microsoft OLE DB 드라이버(MSOLEDBSQL) 또는 최신 Microsoft ODBC Driver for SQL Server로 전환합니다. SQL Server 데이터베이스 엔진(버전 2012부터 2019까지)의 구성 요소로 제공되는 SQLNCLI의 경우 이 수명 주기 예외 지원을 참조하세요.

SQL Server를 사용하면 애플리케이션에서 비동기 데이터베이스 작업을 수행할 수 있습니다. 비동기 처리는 호출 스레드를 차단하지 않고 메서드를 즉시 반환할 수 있도록 합니다. 이를 통해 개발자는 명시적으로 스레드를 만들거나 동기화를 처리하지 않고도 보다 강력하고 유연한 다중 스레딩을 구현할 수 있습니다. 애플리케이션은 데이터베이스 연결을 초기화하거나 명령 실행에서 결과를 초기화할 때 비동기 처리를 요청합니다.

데이터베이스 커넥트 열기 및 닫기

SQL Server Native Client OLE DB 공급자를 사용하는 경우 데이터 원본 개체를 비동기적으로 초기화하도록 설계된 애플리케이션은 IDBInitialize::Initialize를 호출하기 전에 DBPROP_INIT_ASYNCH 속성에서 DBPROPVAL_ASYNCH_INITIALIZE 비트를 설정할 수 있습니다. 이 속성이 설정된 경우 공급자는 Initialize 호출 시 S_OK 또는 DB_S_ASYNCHRONOUS와 함께 즉시 반환됩니다. S_OK는 초기화 작업이 즉시 완료된 경우 반환되고 DB_S_ASYNCHRONOUS는 초기화 작업이 비동기식으로 계속되는 경우 반환됩니다. 애플리케이션은 데이터 원본 개체에서 IDBAsynchStatus 또는 ISSAsynchStatus 인터페이스를 쿼리한 다음 IDBAsynchStatus::GetStatus 또는ISSAsynchStatus::WaitForAsynchCompletion을 호출하여 초기화의 상태 가져올 수 있습니다.

또한 SSPROP_ISSAsynchStatus 속성이 DBPROPSET_SQLSERVERROWSET 속성 집합에 추가되었습니다. ISSAsynchStatus 인터페이스를 지원하는 공급자는 VARIANT_TRUE 값을 사용하여 이 속성을 구현해야 합니다.

IDBAsynchStatus::Abort 또는 ISSAsynchStatus::Abort 를 호출하여 비동 기 초기화 호출을 취소할 수 있습니다. 소비자는 비동기 데이터 원본 초기화를 명시적으로 요청해야 합니다. 그렇지 않으면 데이터 원본 개체가 완전히 초기화될 때까지 IDBInitialize::Initialize 가 반환되지 않습니다.

참고 항목

연결 풀링에 사용되는 데이터 원본 개체는 SQL Server Native Client OLE DB 공급자에서 ISSAsynchStatus 인터페이스를 호출할 수 없습니다. ISSAsynchStatus 인터페이스는 풀된 데이터 원본 개체에 대해 노출되지 않습니다.

애플리케이션이 커서 엔진 사용을 명시적으로 강제하는 경우 IOpenRowset::OpenRowsetIMultipleResults::GetResult 는 비동기 처리를 지원하지 않습니다.

또한 원격 프록시/스텁 dll(MDAC 2.8)은 SQL Server Native Client에서 ISSAsynchStatus 인터페이스를 호출할 수 없습니다. ISSAsynchStatus 인터페이스는 원격을 통해 노출되지 않습니다.

서비스 구성 요소는 ISSAsynchStatus를 지원하지 않습니다.

실행 및 행 집합 초기화

명령 실행으로 인해 결과를 비동기적으로 열도록 설계된 애플리케이션은 DBPROP_ROWSET_ASYNCH 속성에서 DBPROPVAL_ASYNCH_INITIALIZE 비트를 설정할 수 있습니다. IDBInitialize::Initialize, ICommand::Execute, IOpenRowset::OpenRowset 또는 IMultipleResults::GetResult를 호출하기 전에 이 비트를 설정하는 경우 riid 인수는 IID_IDBAsynchStatus, IID_ISSAsynchStatus 또는 IID_IUnknown 설정해야 합니다.

이 메서드는 행 집합 초기화가 즉시 완료되면 S_OK 즉시 반환하거나, 행 집합이 행 집합의 요청된 인터페이스로 설정된 상태에서 행 집합이 비동기적으로 초기화를 계속하면 DB_S_ASYNCHRONOUS 함께 즉시 반환됩니다. SQL Server Native Client OLE DB 공급자의 경우 이 인터페이스는 IDBAsynchStatus 또는 ISSAsynchStatus일 수 있습니다. 행 집합이 완전히 초기화될 때까지 이 인터페이스는 일시 중단 상태에 있는 것처럼 동작하며 인터페이스에 대해 IID_IDBAsynchStatus 또는 IID_ISSAsynchStatus가 아닌 QueryInterface를 호출하면 E_NOINTERFACE가 반환될 수 있습니다. 소비자가 비동기 처리를 명시적으로 요청하지 않는 한 행 집합은 동기적으로 초기화됩니다. 동기화 작업이 완료되었다는 메시지와 함께 IDBAsynchStaus::GetStatus 또는 ISSAsynchStatus::WaitForAsynchCompletion이 반환되면 요청된 모든 인터페이스를 사용할 수 있습니다. 그렇다고 행 집합이 완전히 채워지는 것은 아니지만 완전하고 완벽하게 작동합니다.

실행된 명령이 행 집합을 반환하지 않으면 IDBAsynchStatus를 지원하는 개체를 사용하여 즉시 반환됩니다.

비동기 명령 실행에서 여러 결과를 가져와야 하는 경우 다음을 수행해야 합니다.

  • 명령을 실행하기 전에 DBPROP_ROWSET_ASYNCH 속성의 DBPROPVAL_ASYNCH_INITIALIZE 비트를 설정합니다.

  • ICommand::Execute를 호출하고 IMultipleResults를 요청합니다.

그런 다음 QueryInterface를 사용하여 여러 결과 인터페이스를 쿼리하여 IDBAsynchStatusISSAsynchStatus 인터페이스를 가져올 수 있습니다.

명령 실행 이 완료되면 동기 사례에서 한 가지 예외를 제외하고 IMultipleResults 를 정상적으로 사용할 수 있습니다. DB_S_ASYNCHRONOUS 반환될 수 있습니다. 이 경우 IDBAsynchStatus 또는 ISSAsynchStatus 를 사용하여 작업이 완료되는 시기를 확인할 수 있습니다.

예제

다음 예제에서 애플리케이션은 비차단 메서드를 호출하고, 다른 처리를 수행하고, 결과를 처리하기 위해 반환합니다. ISSAsynchStatus::WaitForAsynchCompletion은 비동기 실행 작업이 수행되거나 dwMilisecTimeOut으로 지정된 시간이 지나갈 때까지 내부 이벤트 개체에서 대기합니다.

// Set the DBPROPVAL_ASYNCH_INITIALIZE bit in the   
// DBPROP_ROWSET_ASYNCH property before calling Execute().  
  
DBPROPSET CmdPropset[1];  
DBPROP CmdProperties[1];  
  
CmdPropset[0].rgProperties = CmdProperties;  
CmdPropset[0].cProperties = 1;  
CmdPropset[0].guidPropertySet = DBPROPSET_ROWSET;  
  
// Set asynch mode for command.  
CmdProperties[0].dwPropertyID = DBPROP_ROWSET_ASYNCH;  
CmdProperties[0].vValue.vt = VT_I4;  
CmdProperties[0].vValue.lVal = DBPROPVAL_ASYNCH_INITIALIZE;  
CmdProperties[0].dwOptions = DBPROPOPTIONS_REQUIRED;  
  
hr = pICommandProps->SetProperties(1, CmdPropset);  
  
hr = pICommand->Execute(  
   pUnkOuter,  
   IID_ISSAsynchStatus,  
   pParams,  
   pcRowsAffected,  
   (IUnknown**)&pISSAsynchStatus);  
  
if (hr == DB_S_ASYNCHRONOUS)  
{  
   // Do some work here...  
  
   hr = pISSAsynchStatus->WaitForAsynchCompletion(dwMilisecTimeOut);  
   if ( hr == S_OK)  
   {  
      hr = pISSAsynchStatus->QueryInterface(IID_IRowset, (void**)&pRowset);  
      pISSAsynchStatus->Release();  
   }  
}  

ISSAsynchStatus::WaitForAsynchCompletion 은 비동기 실행 작업이 수행되거나 dwMilisecTimeOut 값이 전달될 때까지 내부 이벤트 개체에서 대기합니다.

다음 예제에서는 여러 결과 집합을 사용하는 비동기 처리를 보여줍니다.

DBPROP CmdProperties[1];  
  
// Set asynch mode for command.  
CmdProperties[0].dwPropertyID = DBPROP_ROWSET_ASYNCH;  
CmdProperties[0].vValue.vt = VT_I4;  
CmdProperties[0].vValue.lVal = DBPROPVAL_ASYNCH_INITIALIZE;  
  
hr = pICommand->Execute(  
   pUnkOuter,  
   IID_IMultipleResults,  
   pParams,  
   pcRowsAffected,  
   (IUnknown**)&pIMultipleResults);  
  
// Use GetResults for ISSAsynchStatus.  
hr = pIMultipleResults->GetResult(IID_ISSAsynchStatus, (void **) &pISSAsynchStatus);  
  
if (hr == DB_S_ASYNCHRONOUS)  
{  
   // Do some work here...  
  
   hr = pISSAsynchStatus->WaitForAsynchCompletion(dwMilisecTimeOut);  
   if (hr == S_OK)  
   {  
      hr = pISSAsynchStatus->QueryInterface(IID_IRowset, (void**)&pRowset);  
      pISSAsynchStatus->Release();  
   }  
}  

차단을 방지하기 위해 클라이언트는 다음 예제와 같이 실행 중인 비동기 작업의 상태 검사 수 있습니다.

// Set the DBPROPVAL_ASYNCH_INITIALIZE bit in the   
// DBPROP_ROWSET_ASYNCH property before calling Execute().  
hr = pICommand->Execute(  
   pUnkOuter,  
   IID_ISSAsynchStatus,  
   pParams,  
   pcRowsAffected,  
   (IUnknown**)&pISSAsynchStatus);   
  
if (hr == DB_S_ASYNCHRONOUS)  
{  
   do{  
      // Do some work...  
      hr = pISSAsynchStatus->GetStatus(DB_NULL_HCHAPTER, DBASYNCHOP_OPEN, NULL, NULL, &ulAsynchPhase, NULL);  
   }while (DBASYNCHPHASE_COMPLETE != ulAsynchPhase)  
   if SUCCEEDED(hr)  
   {  
      hr = pISSAsynchStatus->QueryInterface(IID_IRowset, (void**)&pRowset);  
   }  
   pIDBAsynchStatus->Release();  
}  

다음 예에서는 현재 실행 중인 비동기 작업을 취소하는 방법을 보여 줍니다.

// Set the DBPROPVAL_ASYNCH_INITIALIZE bit in the   
// DBPROP_ROWSET_ASYNCH property before calling Execute().  
hr = pICommand->Execute(  
   pUnkOuter,  
   IID_ISSAsynchStatus,  
   pParams,  
   pcRowsAffected,  
   (IUnknown**)&pISSAsynchStatus);  
  
if (hr == DB_S_ASYNCHRONOUS)  
{  
   // Do some work...  
   hr = pISSAsynchStatus->Abort(DB_NULL_HCHAPTER, DBASYNCHOP_OPEN);  
}  

참고 항목

SQL Server Native Client 기능
행 집합 속성 및 동작
ISSAsynchStatus(OLE DB)