Perl 多个准备好的语句使用DBD::Sybase中断事务

Perl 多个准备好的语句使用DBD::Sybase中断事务,perl,transactions,sybase,dbi,Perl,Transactions,Sybase,Dbi,在我的Perl脚本中,我使用DBD::Sybase(通过DBI模块)连接到SQLServer2008。以下基本程序运行正常: 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

在我的Perl脚本中,我使用DBD::Sybase(通过DBI模块)连接到SQLServer2008。以下基本程序运行正常:

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
驱动程序运行了相同的代码,对SQLServer2005没有任何问题。(但我的公司升级到2008年,我不得不使用
DBD::Sybase
来解决其他一些问题。)

如能就如何解决此问题提供任何帮助/建议,将不胜感激。特别是,为另一个
prepare
使用不同的db句柄并不是一个理想的解决方案,因为这将超出在单个事务中使用它们的目的


更新:结果表明,如果我对附加插入至少执行一次,那么程序再次正常运行。看起来每个准备好的语句都需要在Sybase下运行。但这不是ODBC的要求,通常也不是合理的要求。无论如何,要绕过它?

结果表明,DBI的
prepare
方法在各种数据库驱动程序中都不是很容易移植的。对于Sybase驱动程序,很可能是
prepare
未按预期工作。一种方法是运行
prepare
后,变量
$insert->{NUM\u OF_FIELDS}
未定义

要解决此问题,请执行以下操作之一:

1) 不要准备任何东西。只需在文本字符串中动态构造语句并运行
$dbh->do($stmt)
,或者


2) 在运行
COMMIT TRAN
之前,对所有未完成的语句句柄(在该数据库句柄下)运行
finish
。我个人更喜欢这种方式。

结果表明,DBI的
prepare
方法并不能像前面提到的那样在各种数据库驱动程序之间进行移植。对于Sybase驱动程序,很可能是
prepare
未按预期工作。一种方法是运行
prepare
后,变量
$insert->{NUM\u OF_FIELDS}
未定义

要解决此问题,请执行以下操作之一:

1) 不要准备任何东西。只需在文本字符串中动态构造语句并运行
$dbh->do($stmt)
,或者


2) 在运行
COMMIT TRAN
之前,对所有未完成的语句句柄(在该数据库句柄下)运行
finish
。我个人更喜欢这种方式。

不要动态创建SQL,这很危险(SQL注入)

您应该能够准备多个插入/更新,并且指向DBI文档的链接并不是说您不能,而是说一些驱动程序可能无法告诉您有关只准备好的语句的更多信息


我将在dbi用户列表中发布一个失败的错误示例,以供评论,因为DBD::Sybase维护器挂在那里(请参阅)。

不要动态创建SQL,这是危险的(SQL注入)

您应该能够准备多个插入/更新,并且指向DBI文档的链接并不是说您不能,而是说一些驱动程序可能无法告诉您有关只准备好的语句的更多信息


我将在dbi用户列表中发布一个失败的错误示例,以供评论,因为DBD::Sybase维护人员挂在那里(请参阅)。

您正在学习perl和Sybase基础知识,并得出了一些错误的结论

暂时忘记它在ODBC下的功能。ODBC很可能已启用自动提交,因此您没有任何事务控制。(当DBD::支持DB-Lib和CT-Lib时,为什么有人会使用ODBC,我不明白,但这是另外一个故事。)

Re:“看来每个准备好的语句都需要在Sybase下运行。”

罗海瑟是对的。通过准备一个批次但执行一个do,您希望实现什么?除了在Sybase下,您还希望在其他什么地方执行在Sybase下准备的批处理

Do与prepare/execute是完全不同的。为Sybase准备/执行在数百万个程序中运行良好。你只需要了解它的作用,而不是你认为它应该做什么。准备让我们加载一个批处理,一个以正常Sybase意义下的GO终止的命令块。Execute执行准备好的批处理(提供GO并将批处理发送到服务器),并捕获返回的内容(根据您设置的任何数组/变量)

Do是即时的、单一的命令,没有准备。准备+执行组合

只执行单个语句do,并且只执行动态SQL,这是非常有限的,而且完全没有必要的,因为这是您可以完成的全部工作

您目前有:

准备:

UPDATE
Execute (100)
ExecuteImmediate(Do):
COMMIT TRAN
BEGIN TRAN
UPDATE
COMMIT TRAN
因此,当然,没有BEGIN TRAN。(执行第一个“do”时,BEGIN TRAN不见了)

我想你想要的(原本打算的)是这个。忘记“该做的事”:

准备:

UPDATE
Execute (100)
ExecuteImmediate(Do):
COMMIT TRAN
BEGIN TRAN
UPDATE
COMMIT TRAN
执行(100)

然后将其更改为:

BEGIN TRAN
INSERT
UPDATE
COMMIT TRAN
执行(100)

你的$Update和$INSERT会混淆你(你正在执行一个多语句批处理,对吗?不是在准备批处理中间的一个孤立的单个命令)。如果您摆脱了它们,并以$execute(您在批处理中准备的任何东西)为基础进行思考,它可能会帮助您更好地理解问题

在完成上述所有工作之前,不要形成结论

并阅读BEGIN/COMMIT TRAN


最后,到底什么是“
END-TRAN
”?我认为您发布的代码块不是真实的。

您正在学习perl和Sybase基础知识,并得出了一些错误的结论

暂时忘记它在ODBC下的功能。ODBC most问题