Почему ADO BeginTrans () делает что-то отличное от «BEGIN TRANSACTION»? - PullRequest
2 голосов
/ 22 октября 2010

Я столкнулся с неожиданным поведением при использовании ADO с C ++ и Microsoft SQL Server 2008 (экспресс). По сути, у меня был код, который сделал это:

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

Но когда он попытался выполнить SelectAll, ADO выдал исключение со следующей информацией:

Ошибка: ошибка ADO -2147217871: 071A14D0
Из источника: поставщик Microsoft OLE DB для SQL Server
Описание: Время ожидания истекло

После небольшого перерыва я обнаружил, что, если бы я использовал ado_connection-> BeginTrans (), как это делал бы здравомыслящий человек, все работало как ожидалось. И хотя этот пост в основном предназначен для того, чтобы обойти эту проблему для других людей, которые могут с ней столкнуться, у меня также есть вопрос:

Почему это решило проблему?

Вот немного подробнее о том, что происходит с моими Insert и SelectAll. Обратите внимание, что SelectAll использует объект команды ADO (потому что в реальном коде он не делает выбор всех). Тайм-аут не возникает, если я использую 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 Ответ

1 голос
/ 22 октября 2010

Короткий ответ: BEGIN TRANSACTION и cn.BeginTrans() ведут себя не всегда одинаково.Эта статья MSDN рассказывает вам больше об этой проблеме:


Как 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

... а также, возможно, не то, что вы ожидаете.

...