Pourquoi est-ce que ADO BeginTrans () fait quelque chose de différent de "BEGIN TRANSACTION"?

J'ai rencontré un comportement surprenant lors de l'utilisation d'ADO avec C ++ et Microsoft SQL Server 2008 (express). Essentiellement, j'ai eu le code qui a fait ceci:

//pseudocode pseudocode pseudocode adoConnection->Execute("BEGIN TRANSACTION;"); Insert( adoRecordsetPtr ); SelectAll( adoRecordsetPtr ); adoConnection->Execute("COMMIT TRANSACTION;"); 

Mais quand il a essayé d'effectuer le SelectAll, ADO a jeté une exception avec les informations suivantes:

Erreur: Erreur ADO -2147217871: 071A14D0
De la source: Fournisseur Microsoft OLE DB pour SQL Server
Description: Expiration du timeout

Après un peu de search, j'ai découvert que si j'utilisais ado_connection-> BeginTrans (), comme le ferait une personne sensée, tout a fonctionné comme prévu. Et bien que ce post soit principalement ici pour rendre la solution de contournement accessible à d'autres personnes susceptibles de la rencontrer, j'ai aussi une question:

Pourquoi cela a-t-il résolu le problème?

Voici un peu plus de détails sur ce qui se passe avec mon Insert et SelectAll. Notez que SelectAll utilise un object de command ADO (car dans le code actuel, il ne fait pas tout sélectionner). Le timeout d'attente ne se produit pas si j'utilise Connection.Execute () au lieu de Command.Execute ().

 //Insert ADODB::_RecordsetPtr prs = NULL; HRESULT hr = prs.CreateInstance(__uuidof(ADODB::Recordset)); prs->Open( table _variant_t((IDispatch *) acpAdoConnection), ADODB::adOpenUnspecified, ADODB::adLockOptimistic, ADODB::adCmdTable); prs->AddNew(); //put some stuff into fields using prs->Fields->Item[] prs->Update(); prs->Close(); //SelectAll ADODB::_CommandPtr cmd; cmd.CreateInstance( __uuidof( ADODB::Command ) ); cmd->ActiveConnection = acpAdoConnection; ADODB::_RecordsetPtr prs2 = NULL; HRESULT hr2 = prs2.CreateInstance(__uuidof(ADODB::Recordset)); prs2->Open( table, _variant_t((IDispatch *) acpAdoConnection), ADODB::adOpenUnspecified, ADODB::adLockOptimistic, ADODB::adCmdTable); std::ssortingng sql = "SELECT * FROM [" + table + "] ;"; cmd->CommandText = sql.c_str(); _variant_t vtEmpty (DISP_E_PARAMNOTFOUND, VT_ERROR); _variant_t vtEmpty2(DISP_E_PARAMNOTFOUND, VT_ERROR); //timeout: ADODB::_RecordsetPtr records = cmd->Execute( &vtEmpty, &vtEmpty2, ADODB::adCmdText ); 

La réponse courte est que BEGIN TRANSACTION et cn.BeginTrans() ne se comportent pas toujours de la même manière. Cet article MSDN vous en dit plus sur ce problème:


Comment se comporte ADO en ce qui concerne les transactions

Par défaut, ADO fonctionne en mode AutoCommit, sauf si vous démarrez une transaction implicite en exécutant Connection.BeginTrans.

Implicit_transactions commence une transaction sur le server pour chaque instruction, et les validations ne se produisent pas jusqu'à ce qu'elles soient émises manuellement.

Alors,

 set implicit_transactions on go insert insert insert 

est intérieurement transformé en

 BEGIN TRAN insert insert insert ... 

La transaction ci-dessus ne sera pas annulée ou validée à less que l'user n'émette l'instruction correcte.

Sans transaction implicite, qui est par défaut le comportement de ADO (mode de validation automatique), ce qui suit est (conceptuellement) survenant:

 BEGIN TRAN insert COMMIT TRAN BEGIN TRAN insert COMMIT TRAN 

Comme vous pouvez le voir facilement, pour votre cas

 BEGIN TRAN insert COMMIT TRAN BEGIN TRAN select COMMIT TRAN 

est différent de:

 BEGIN TRAN insert select COMMIT TRAN 

… et aussi peut-être pas ce que vous attendez.