分享方式:


在 SQL Server Native Client 中執行異步操作

適用於:SQL ServerAzure SQL DatabaseAzure SQL 受控執行個體Azure Synapse AnalyticsAnalytics Platform System (PDW)

重要

SQL Server Native Client (SNAC) 未隨附於:

  • SQL Server 2022 (16.x) 和更新版本
  • SQL Server Management Studio 19 和更新版本

不建議使用 SQL Server Native Client (SQLNCLI 或 SQLNCLI11) 和舊版 Microsoft OLE DB Provider for SQL Server (SQLOLEDB) 開發新的應用程式。

針對新專案,請使用下列其中一個驅動程式:

針對 SQL Server 資料庫引擎 (2012 到 2019 版) 的隨附元件 SQLNCLI,請參閱支援生命週期例外狀況

SQL Server 允許應用程式執行非同步資料庫作業。 非同步處理可讓方法立即執行,而不會在呼叫的執行緒上封鎖。 這樣可允許多執行緒的許多功能與彈性,而不需要開發人員明確建立執行緒或處理同步。 當初始化資料庫連接或初始化執行命令的結果時,應用程式會要求非同步處理。

開啟及關閉資料庫連接

使用 SQL Server Native Client OLE DB 提供者時,設計來初始化數據源物件的應用程式可以在呼叫 IDBInitialize::Initialize 之前,先在 DBPROP_INIT_ASYNCH 屬性中設定DBPROPVAL_ASYNCH_INITIALIZE位。 設定此屬性時,如果作業已經立即完成,提供者會使用 S_OK 立即從 Initialize 的呼叫傳回;如果初始化是以非同步方式繼續,則會使用 DB_S_ASYNCHRONOUS 從此呼叫傳回。 應用程式可以在數據源對象上查詢 IDBAsynchStatus 或 ISSAsynchStatus 介面,然後呼叫 IDBAsynchStatus::GetStatusISSAsynchStatus::WaitForAsynchCompletion 以取得初始化的狀態。

此外,SSPROP_ISSAsynchStatus 屬性已加入到 DBPROPSET_SQLSERVERROWSET 屬性集。 支援 ISSAsynchStatus 介面的提供者必須使用 VARIANT_TRUE 的值實作此屬性。

呼叫 IDBAsynchStatus::AbortISSAsynchStatus::Abort 可以取消非同步的 Initialize 呼叫。 取用者必須明確地要求非同步資料來源初始化。 否則,要等到資料來源物件完全初始化之後,IDBInitialize::Initialize 才會傳回。

注意

用於連接共享的數據源對象無法呼叫 SQL Server Native Client OLE DB 提供者中的 ISSAsynchStatus 介面。 ISSAsynchStatus 介面不會針對集區資料來源物件公開。

如果應用程式明確地強制使用資料指標引擎,IOpenRowset::OpenRowsetIMultipleResults::GetResult 將不支援非同步處理。

此外,遠端 Proxy/存根 dll (在 MDAC 2.8 中) 無法呼叫 SQL Server Native Client 中的 ISSAsynchStatus 介面。 ISSAsynchStatus 介面不會透過遠端公開。

服務元件不支援 ISSAsynchStatus

執行和資料列集初始化

設計為非同步開啟執行命令結果的應用程式可以在 DBPROP_ROWSET_ASYNCH 屬性中設定 DBPROPVAL_ASYNCH_INITIALIZE 位元。 呼叫 IDBInitialize::InitializeICommand::ExecuteIOpenRowset::OpenRowsetIMultipleResults::GetResult 之前設定此位元時,必須將 riid 引數設定為 IID_IDBAsynchStatus、IID_ISSAsynchStatus 或 IID_Iunknown。

如果資料列集初始化立即完成,此方法會使用 S_OK 立即傳回;如果資料列集在 ppRowset 設定為資料列集上要求的介面時,繼續以非同步方式初始化,則會使用 DB_S_ASYNCHRONOUS 傳回此方法。 針對 SQL Server Native Client OLE DB 提供者,此介面只能是 IDBAsynchStatusISSAsynchStatus。 在資料列集完全初始化之前,此介面的行為如同處於已暫停狀態,而且針對 IID_IDBAsynchStatusIID_ISSAsynchStatus 之外的介面呼叫 QueryInterface 可能會傳回 E_NOINTERFACE。 除非取用者明確地要求非同步處理,否則資料列集會以同步的方式進行初始化。 如果 IDBAsynchStaus::GetStatusISSAsynchStatus::WaitForAsynchCompletion 傳回時,指出非同步作業已完成,則可使用所有要求的介面。 這不一定表示資料列集已完全擴展,但是該資料列集是完整的,而且完全可以運作。

如果執行的命令並未傳回資料列集,它仍然會使用支援 IDBAsynchStatus 的物件立即傳回。

如果您需要從非同步命令執行取得多個結果,您應該:

  • 在執行命令之前,設定 DBPROP_ROWSET_ASYNCH 屬性的 DBPROPVAL_ASYNCH_INITIALIZE 位元。

  • 呼叫 ICommand::Execute,並要求 IMultipleResults

接著,使用 QueryInterface 來查詢多個結果介面,藉此取得 IDBAsynchStatusISSAsynchStatus 介面。

當命令執行完成時,除非同步案例的一個例外,否則可以如常使用 IMultipleResults:可以傳回 DB_S_ASYNCHRONOUS,在此情況下,IDBAsynchStatusISSAsynchStatus 可用於判斷作業完成的時間。

範例

在下列範例中,應用程式會呼叫非封鎖的方法、進行其他某些處理,然後返回處理結果。 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)