Partilhar via


Executando operações assíncronas

O SQL Server permite que os aplicativos executem operações de banco de dados assíncronas. O processamento assíncrono permite que os métodos retornem imediatamente sem bloquear o thread de chamada. Isso permite grande parte do poder e flexibilidade do multithreading, sem exigir que o desenvolvedor crie explicitamente threads ou manipule a sincronização. Os aplicativos solicitam processamento assíncrono ao inicializar uma conexão de banco de dados ou ao inicializar o resultado da execução de um comando.

Abrir e fechar uma conexão de banco de dados

Ao usar o provedor OLE DB do SQL Server Native Client, os aplicativos projetados para inicializar um objeto de fonte de dados de forma assíncrona podem definir o bit DBPROPVAL_ASYNCH_INITIALIZE na propriedade DBPROP_INIT_ASYNCH antes de chamar IDBInitialize::Initialize. Quando essa propriedade é definida, o provedor retorna imediatamente da chamada para Inicializar com S_OK, se a operação tiver sido concluída imediatamente ou DB_S_ASYNCHRONOUS, se a inicialização continuar de forma assíncrona. Os aplicativos podem consultar a interface IDBAsynchStatus ou ISSAsynchStatusno objeto de fonte de dados e chamar IDBAsynchStatus::GetStatus ouISSAsynchStatus::WaitForAsynchCompletion para obter o status da inicialização.

Além disso, a propriedade SSPROP_ISSAsynchStatus foi adicionada ao conjunto de propriedades DBPROPSET_SQLSERVERROWSET. Os provedores que dão suporte à interface ISSAsynchStatus devem implementar essa propriedade com um valor de VARIANT_TRUE.

IDBAsynchStatus::Abort ou ISSAsynchStatus::Abort pode ser chamado para cancelar a chamada de inicialização assíncrona. O consumidor deve solicitar explicitamente a inicialização assíncrona da fonte de dados. Caso contrário, IDBInitialize::Initialize não retornará até que o objeto da fonte de dados seja completamente inicializado.

Observação

Os objetos de fonte de dados usados para o pool de conexões não podem chamar a interface ISSAsynchStatus no provedor OLE DB do SQL Server Native Client. A interface ISSAsynchStatus não é exposta para objetos de fonte de dados em pool.

Se um aplicativo força explicitamente o uso do mecanismo de cursor, IOpenRowset::OpenRowset e IMultipleResults::GetResult não oferecerão suporte ao processamento assíncrono.

Além disso, o proxy/stub dll de comunicação remota (no MDAC 2.8) não pode chamar a interface ISSAsynchStatus no SQL Server Native Client. A interface ISSAsynchStatus não é exposta por meio da comunicação remota.

Os Componentes de Serviço não dão suporte a ISSAsynchStatus.

Inicialização de execução e conjunto de linhas

Aplicativos projetados para abrir de forma assíncrona o resultado da execução de um comando podem definir o bit DBPROPVAL_ASYNCH_INITIALIZE na propriedade DBPROP_ROWSET_ASYNCH. Ao definir esse bit antes de chamar IDBInitialize::Initialize, ICommand::Execute, IOpenRowset::OpenRowset ou IMultipleResults::GetResult, o argumento riid deve ser definido como IID_IDBAsynchStatus, IID_ISSAsynchStatus ou IID_IUnknown.

O método retorna imediatamente com S_OK se a inicialização do conjunto de linhas for concluída imediatamente ou com DB_S_ASYNCHRONOUS se o conjunto de linhas continuar inicializando de forma assíncrona, com ppRowset definido como a interface solicitada no conjunto de linhas. Para o provedor OLE DB do SQL Server Native Client, essa interface só pode ser IDBAsynchStatus ou ISSAsynchStatus. Até que o conjunto de linhas seja totalmente inicializado, essa interface se comporta como se estivesse em um estado suspenso e chamar QueryInterface para interfaces diferentes de IID_IDBAsynchStatus ou IID_ISSAsynchStatus pode retornar E_NOINTERFACE. A menos que o consumidor solicite explicitamente o processamento assíncrono, o conjunto de linhas é inicializado de forma síncrona. Todas as interfaces solicitadas estão disponíveis quando IDBAsynchStaus::GetStatus ou ISSAsynchStatus::WaitForAsynchCompletion retorna com a indicação de que a operação assíncrona está concluída. Isso não significa necessariamente que o conjunto de linhas está totalmente preenchido, mas é completo e totalmente funcional.

Se o comando executado não retornar um conjunto de linhas, ele ainda retornará imediatamente com um objeto que dá suporte a IDBAsynchStatus.

Se você precisar obter vários resultados da execução de comando assíncrono, deverá:

  • Defina o bit DBPROPVAL_ASYNCH_INITIALIZE da propriedade DBPROP_ROWSET_ASYNCH antes de executar o comando.

  • Chame ICommand::Execute e solicite IMultipleResults.

As interfaces IDBAsynchStatus e ISSAsynchStatus podem ser obtidas consultando a interface de vários resultados usando QueryInterface.

Quando o comando terminar de ser executado, IMultipleResults poderá ser usado normalmente, com uma exceção do caso síncrono: DB_S_ASYNCHRONOUS podem ser retornados; nesse caso, IDBAsynchStatus ou ISSAsynchStatus pode ser usado para determinar quando a operação é concluída.

Exemplos

No exemplo a seguir, o aplicativo chama um método de não bloqueio, faz algum outro processamento e retorna para processar os resultados. ISSAsynchStatus::WaitForAsynchCompletion aguarda o objeto de evento interno até que a operação de execução assíncrona seja concluída ou o tempo especificado pelo dwMilisecTimeOut seja passado.

// 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 aguarda o objeto de evento interno até que a operação de execução assíncrona seja concluída ou o valor dwMilisecTimeOut seja passado.

O exemplo a seguir mostra o processamento assíncrono com vários conjuntos de resultados:

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

Para evitar o bloqueio, o cliente pode verificar o status de uma operação assíncrona em execução, como no exemplo a seguir:

// 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();  
}  

O exemplo a seguir demonstra como você pode cancelar a operação assíncrona em execução no momento:

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

Consulte Também

Recursos do SQL Server Native Client
Propriedades e comportamentos do conjunto de linhas
ISSAsynchStatus (OLE DB)