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 serem bloqueados no thread de chamada. Isto permite muito do poder e flexibilidade de multithreading, sem exigir que o desenvolvedor crie threads explicitamente ou controle 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.
Abrindo e fechando 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 assincronamente podem definir o bit DBPROPVAL_ASYNCH_INITIALIZE na propriedade DBPROP_INIT_ASYNCH antes de chamar IDBInitialize::Initialize. Quando essa propriedade for definida, o provedor será retornado imediatamente da chamada para inicializar com S_OK, se a operação tiver sido concluída imediatamente, ou com DB_S_ASYNCHRONOUS, se a inicialização estiver continuando assincronamente. Os aplicativos podem consultar a interface IDBAsynchStatus ou ISSAsynchStatusno objeto de fonte de dados e, em seguida, 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 chamada para cancelar a chamada Initialize assíncrona. O consumidor deve solicitar explicitamente a Inicialização Assíncrona da Fonte de Dados. Caso contrário, IDBInitialize::Initialize não será retornada enquanto o objeto de fonte de dados não for completamente inicializado.
Observação |
---|
Os objetos de fonte de dados usados para o pooling de conexão não podem chamar a interface ISSAsynchStatus no provedor OLE DB do SQL Server Native Client. A interface ISSAsynchStatus não é exposta para objetos da fonte de dados inseridos em pool. Se um aplicativo forçar explicitamente o uso do mecanismo de cursor, IOpenRowset::OpenRowset e IMultipleResults::GetResult não darão suporte ao processamento assíncrono. Além disso, o proxy remoto/dll de stub (no MDAC 2.8) não pode chamar a interface ISSAsynchStatus no SQL Server Native Client. A interface ISSAsynchStatus não é exposta por comunicação remota. Os Componentes de Serviço não têm suporte para a interface ISSAsynchStatus. |
Execução e inicialização de conjunto de linhas
Os aplicativos projetados para abrir assincronamente 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 será retornado 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 assincronamente, com ppRowset definido para a interface solicitada no conjunto de linhas. Para o provedor OLE DB do SQL Server Native Client, esta interface pode ser apenas IDBAsynchStatus ou ISSAsynchStatus. Até o conjunto de linhas ser completamente inicializado, essa interface se comportará como se estivesse em um estado suspenso, e chamar QueryInterface para interfaces diferentes de IID_IDBAsynchStatus ou IID_ISSAsynchStatus poderá retornar E_NOINTERFACE. A menos que o consumidor solicite processamento assíncrono explicitamente, o conjunto de linhas é inicializado sincronamente. 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 é concluída. Isto não significa necessariamente que todo o conjunto de linhas esteja preenchido, mas que está completo e totalmente funcional.
Se o comando executado não retornar um conjunto de linhas, ainda retornará imediatamente com um objeto que dá suporte a IDBAsynchStatus.
Se você precisar obter vários resultados da execução de comando assíncrona, deverá:
Definir o bit DBPROPVAL_ASYNCH_INITIALIZE da propriedade DBPROP_ROWSET_ASYNCH antes de executar o comando.
Chamar ICommand::Execute e solicitar IMultipleResults.
As interfaces IDBAsynchStatus e ISSAsynchStatus podem ser obtidas consultando a interface de vários resultados usando QueryInterface.
Quando o comando tiver concluído a execução, IMultipleResults poderá ser usada como normal, com uma exceção do caso síncrono: DB_S_ASYNCHRONOUS pode ser retornado, caso em que a interface IDBAsynchStatus ou ISSAsynchStatus pode ser usada para determinar quando a operação é concluída.
Exemplos
No exemplo a seguir, o aplicativo chama um método sem-bloqueio, executa algum outro processamento e retorna para processar os resultados. ISSAsynchStatus::WaitForAsynchCompletion espera no objeto de evento interno até que a operação de execução assíncrona seja concluída ou que o tempo especificado por dwMilisecTimeOut seja excedido.
// 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 espera no objeto de evento interno até que a operação de execução assíncrona seja concluída ou o valor de dwMilisecTimeOut seja excedido.
O exemplo a seguir mostra 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 impedir 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 atualmente em execução:
// 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
Referência
Conceitos
Propriedades e comportamentos do conjunto de linhas