Проблема с транзакцией SQL-сервера с использованием Perl DBI

У меня есть приведенный ниже блок кода с оператором INSERT и UPDATE внутри блока BEGIN TRAN и END TRAN.

Теперь мы все знаем, что эта операция атомарна. Но я вижу другое. вставка завершается неудачно из-за нарушения уникального ограничения, но все же происходит ОБНОВЛЕНИЕ. Когда я выполняю ту же часть непосредственно на SQL-сервере, я вижу, что операция совершенно атомарна. Есть ли что-нибудь на фронте PERL DBI, что переопределяет BEGIN TRAN и COMMIT TRAN. Любые указатели?

$dbh->{RaiseError} = 1;
$dbh->{PrintError} = 1;

my $sql = "BEGIN  TRAN

         INSERT INTO $table ...

         UPDATE $table ....

         COMMIT TRAN";
$dbh->do($sql);

person Gopalakrishnan SA    schedule 24.02.2011    source источник


Ответы (1)


Я предполагаю, что вы используете DBD::ODBC, так что имейте это в виду, когда будете читать следующее.

По умолчанию DBI находится в режиме AutoCommit, если вы его не отключили.

Не передавайте несколько фрагментов SQL, использующих подобные транзакции, в SQL Server с помощью метода do, так как DBD::ODBC будет использовать SQLExecDirect для do по умолчанию, а do на самом деле не разработан с учетом нескольких операторов. Вам лучше использовать подготовку/выполнение или разделение вашего SQL и выполнение фиксации в Perl следующим образом:

$dbh->{RaiseError} = 1;
$dbh->begin_work;
eval {
  $dbh->do(q/insert.../);
  $dbh->do(q/update.../);
  $dbh->commit;
  1;
};
if ($@) {
  $dbh->rollback or warn "rollback failed";
}

или поместить вашу вставку/обновление в процедуру SQL Server.

person bohica    schedule 24.02.2011
comment
Да, мы используем DBD::ODBC, поэтому мы можем сделать $dbh-›{'AutoCommit'} = 0; ? так как у нас есть все запросы, вызываемые из кода Perl с использованием $dbh-›do, и у нас есть все запросы внутри блока BEGIN TRAN и COMMIT TRAN - person Gopalakrishnan SA; 24.02.2011
comment
Вы можете попробовать отключить AutoCommit, но я не уверен, что это решит всю проблему. Просто не рекомендуется использовать несколько операторов sql. - person bohica; 24.02.2011
comment
Спасибо, bohica. Есть ли какой-либо другой драйвер, который я могу использовать, кроме DBD::ODBC, чтобы у меня все еще мог быть $dbh-›do($sql) , где $sql имеет BEGIN TRAN, за которым следуют операторы INSERT/UPDATE, за которыми следует END TRAN . Если это известная проблема с DBD::ODBC, то может ли любая другая библиотека решить мою проблему и сделать транзакцию по-прежнему атомарной, не беспокоясь о настройке AutoCommit и выполнении фиксации каждый раз? - person Gopalakrishnan SA; 25.02.2011
comment
Привет Bohica - я пробовал с -›begin_work, и он отлично работает. У меня также есть операторы $dbh-›prepare(), в которых за BEGIN TRAN следует оператор INSERT/UPDATE, за которым следует END TRAN. Теперь, если я выполню $dbh->execute() подготовленного блока, будет ли он атомарным (даже если произойдут нарушения ограничений) или он подвержен таким проблемам, как $dbh->do() - person Gopalakrishnan SA; 25.02.2011