2 votes

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

J'ai rencontré un comportement surprenant en utilisant ADO avec C++ et Microsoft SQL Server 2008 (express). Essentiellement, j'avais du code qui faisait ceci :

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

Mais lorsqu'il a essayé d'exécuter le SelectAll, ADO a déclenché une exception avec les informations suivantes :

Erreur : Erreur ADO -2147217871 : 071A14D0
De la source : Microsoft OLE DB Provider for SQL Server
Description : Le délai d'attente a expiré

Après quelques recherches, j'ai découvert que si j'utilisais ado_connection->BeginTrans(), comme le ferait une personne saine d'esprit, tout fonctionnait comme prévu. Et bien que ce post soit surtout là pour rendre la solution de contournement googlelisable pour d'autres personnes qui pourraient la rencontrer, j'ai aussi une question :

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

Voici un peu plus de détails sur ce qui se passe avec mon Insert et mon SelectAll. Notez que SelectAll utilise un objet de commande ADO (car dans le code actuel, il ne s'agit pas d'une sélection). Le délai 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::string 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 );

1voto

MicSim Points 12980

La réponse courte est que BEGIN TRANSACTION y cn.BeginTrans() ne se comportent pas toujours de la même façon. Ce site Article de MSDN vous en dit plus sur ce problème :


Comment ADO se comporte-t-il par rapport aux 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 serveur pour chaque déclaration, et les commits ne se produisent pas tant qu'ils ne sont pas émis manuellement.

Donc,

set implicit_transactions on
go
insert
insert
insert

est transformé en interne en

BEGIN TRAN
insert
insert
insert
...

La transaction ci-dessus ne sera pas annulée ou validée si l'utilisateur n'émet pas la déclaration correcte.

Sans transaction implicite, qui est par défaut le comportement d'ADO (mode Auto Commit), ce qui suit se produit (conceptuellement) :

BEGIN TRAN
insert
COMMIT TRAN
BEGIN TRAN
insert
COMMIT TRAN

Comme vous pouvez le voir, 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.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X