为什么ADO BeginTrans()做的不同于“BEGIN TRANSACTION”?

时间:2010-10-22 15:12:31

标签: c++ sql-server ado

在将ADO与C ++和Microsoft SQL Server 2008(express)一起使用时,我遇到了一些令人惊讶的行为。基本上,我有代码执行此操作:

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

但是当它试图执行SelectAll时,ADO抛出了一个包含以下信息的异常:

错误:ADO错误-2147217871:071A14D0
源自:用于SQL Server的Microsoft OLE DB提供程序
说明:超时已过期

经过一番调查,我发现如果我使用ado_connection-> BeginTrans(),就像一个理智的人一样,一切都按预期工作。虽然这篇文章主要是为了让其他可能遇到它的人可以使用变通方法,但我也有一个问题:

为什么这样可以解决问题?

以下是有关Insert和SelectAll正在发生的事情的详细信息。请注意,SelectAll正在使用ADO命令对象(因为在实际代码中它没有执行select all)。如果我使用Connection.Execute()而不是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 );

1 个答案:

答案 0 :(得分:1)

简短的回答是BEGIN TRANSACTIONcn.BeginTrans()的行为方式并不一样。这个MSDN article会告诉您有关此问题的更多信息:


ADO如何处理交易

默认情况下,ADO在AutoCommit模式下运行,除非您通过执行Connection.BeginTrans启动隐式事务。

Implicit_transactions在服务器上为每个语句开始一个事务,并且在手动发出提交之前不会发生提交。

所以,

set implicit_transactions on
go
insert
insert
insert

内部变为

BEGIN TRAN
insert
insert
insert
...

除非用户发出正确的声明,否则不会回滚或提交上述事务。

没有隐式事务,默认情况下是ADO(自动提交模式)的行为,以下是(概念上)发生的:

BEGIN TRAN
insert
COMMIT TRAN
BEGIN TRAN
insert
COMMIT TRAN

正如您可以轻松看到的那样,

BEGIN TRAN
insert
COMMIT TRAN
BEGIN TRAN
select
COMMIT TRAN

不同于:

BEGIN TRAN
insert
select
COMMIT TRAN

......也许不是你所期待的。