Несколько подготовленных операторов нарушают транзакцию, используя DBD :: Sybase - PullRequest
1 голос
/ 06 октября 2010

В моем скрипте Perl я использую DBD :: Sybase (через модуль DBI) для подключения к SQL Server 2008. Базовая программа, как показано ниже, запускается без проблем:

use DBI;

# assign values to $host, $usr, $pwd
my $dbh = DBI->connect("dbi:Sybase:$host", $usr, $pwd);
$dbh->do("BEGIN TRAN tr1");
my $update = $dbh->prepare("UPDATE mytable SET qty = ? where name = ?");
$update->execute(100, 'apple');
$dbh->do("END TRAN tr1");

однако, если я вставлюеще один оператор prepare прямо перед существующим оператором prepare, чтобы программа выглядела как:

...
my $insert = $dbh->prepare("INSERT INTO mytable (name, qty) VALUES (?, ?)");
my $update = $dbh->prepare("UPDATE mytable SET qty = ? where name = ?");
...

, а все остальное - то же самое, затем, когда я ее запускаю, я получаю:

DBD::Sybase::db do failed: Server message number=3902 severity=16 state=1 line=1 server=xxx text=The COMMIT TRANSACTION request has no corresponding BEGIN TRANSACTION.

Похоже, что дополнительный оператор prepare каким-то образом нарушил весь поток транзакций.Я выполнял тот же код через драйвер DBD::ODBC без проблем с SQL SERVER 2005. (Но моя фирма обновилась до 2008, и мне пришлось использовать DBD::Sybase, чтобы обойти некоторые другие проблемы.)

Любая помощь / предложение о том, как решить эту проблему, будет принята с благодарностью.В частности, использование другого дескриптора db для другого prepare не является желательным решением, поскольку оно побьет цель иметь их в одной транзакции.

UPDATE: Получается, еслиЯ выполняю хотя бы один раз на дополнительной вставке, затем программа снова запускается нормально.Похоже, что каждое подготовленное утверждение должно выполняться под Sybase.Но это не является обязательным требованием для ODBC и вообще не является разумным требованием.В любом случае, чтобы обойти это?

Ответы [ 3 ]

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

Вы изучаете основы Perl и Sybase и делаете несколько неверных выводов.

Забудьте о том, что он делает под ODBC на мгновение. Скорее всего, в ODBC включен AUTOCOMMIT, и, таким образом, вы не имеете никакого контроля транзакций. (Почему кто-то будет использовать ODBC, когда DBD :: поддерживает DB-Lib и CT-Lib мне не подходит, но это отдельная история.)

Re: "Похоже, что каждый подготовленный оператор должен выполняться в Sybase."

Rawheiser правильный. Чего именно вы ожидаете достичь, готовя партию, а вместо этого выполняя Do? Где еще вы ожидаете выполнить пакет, подготовленный в Sybase, кроме Sybase?

Существуют ли различия между подготовкой и выполнением. Подготовка / выполнение для Sybase прекрасно работает в миллионах программ. вам просто нужно узнать, что он делает, а не то, что, по вашему мнению, он должен делать. подготовим давайте загрузим пакет, блок команд, завершенных GO в обычном смысле Sybase. Execute выполняет подготовленный пакет (передает GO и отправляет пакет на сервер) и захватывает все, что возвращается (в зависимости от того, какой массив / переменные вы установили).

Do - немедленная, единственная команда без подготовки. Подготовка + выполнение вместе взятых.

Выполнение только однократных операторов и только динамического SQL, просто потому, что это все, что вы можете получить, очень ограниченно и совершенно не нужно.

В данный момент у вас есть:

Приготовьте:

UPDATE
Execute (100)
ExecuteImmediate(Do):
COMMIT TRAN

Так что, конечно, нет BEGIN TRAN. (Выполнено первое «do», BEGIN TRAN пропал)

Я думаю, что вы хотите (изначально задумано) это. Забудьте «сделать»:

Подготовка:

BEGIN TRAN
UPDATE
COMMIT TRAN

Выполнить (100)

Затем измените его на:

BEGIN TRAN
INSERT
UPDATE
COMMIT TRAN

Выполнить (100)

Ваши $ update и $ insert приведут вас в замешательство (вы выполняете пакет из нескольких операторов, верно? Не отдельная отдельная команда в середине пакета подготовки). Если вы избавитесь от них и будете думать с точки зрения $ execute [независимо от того, что вы подготовили в пакете], это может помочь вам лучше понять проблему.

Не делайте выводов, пока все вышеперечисленное не будет работать как задумано.

И почитайте о BEGIN / COMMIT TRAN.

Последнее, что такое "END TRAN"? Я не думаю, что блок кода, который вы разместили, является реальным.

0 голосов
/ 07 октября 2010

Не создавайте динамически SQL, это опасно (внедрение SQL).

Вы должны быть в состоянии подготовить несколько вставок / обновлений, и ваша ссылка на документацию DBI не говорит, что вы не можете, она говорит, что некоторые драйверы могут быть не в состоянии рассказать вам много об утверждении, которое подготовлено ТОЛЬКО.

Я бы опубликовал ошибочный пример с ошибкой в ​​списке dbi-users для комментариев, поскольку сопровождающий DBD :: Sybase там висит (см. dbi.perl.org ).

0 голосов
/ 06 октября 2010

Оказывается, что метод DBI prepare не совсем переносим между различными драйверами базы данных, как отмечено здесь . Для драйвера Sybase наиболее вероятно, что prepare не работает должным образом. Один из способов сказать, что после запуска prepare переменная $insert->{NUM_OF_FIELDS} не определена.

Чтобы обойти проблему, выполните одно из следующих действий:

1) не готовить ничего. Просто динамически создайте оператор в текстовой строке и запустите $dbh->do($stmt) или

2) перед запуском COMMIT TRAN запустите finish на всех выдающихся дескрипторах операторов (под этим дескриптором базы данных). Я лично предпочитаю этот способ намного лучше.

...