在我的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
解决其他一些问题。)
非常感谢有关如何解决此问题的任何帮助/建议。特别是,为另一个prepare
使用不同的数据库句柄不是一个理想的解决方案,因为这样做会超过在单个事务中使用它们的目的。
UPDATE:如果我在附加插件上至少执行一次,那么程序再次正常运行。所以看起来每个准备好的语句都需要在Sybase下运行。但这不是ODBC的要求,并且通常不是合理的要求。无论如何要绕过它?
答案 0 :(得分:1)
您正在学习perl和Sybase的基础知识并得出一些不正确的结论。
忘掉它在ODBC下做了什么。 ODBC很可能已打开AUTOCOMMIT,因此您没有任何事务控制。 (当DBD ::支持DB-Lib和CT-Lib时,为什么有人会使用ODBC,但这是一个单独的故事。)
Re:“所以看起来每个准备好的语句都需要在Sybase下运行。”
Rawheiser是对的。您期望通过准备批次但执行Do来实现什么?您希望在Sybase以外的其他地方执行哪些批处理,而不是在Sybase下执行?
vs准备/执行是完全不同的。准备/执行Sybase在数百万个程序中运行良好。你只需要了解它的作用,而不是你认为它应该做什么。准备让你加载一个批处理,一个在正常的Sybase意义上由GO终止的命令块。执行执行准备好的批处理(提供GO并将批处理发送到服务器),并捕获返回的任何内容(根据您设置的任何数组/变量)。
做即时,单一命令,没有准备。准备+执行合并。
只执行单个语句do,而且只执行动态SQL,因为这是你可以开始工作的全部内容,非常有限且非常不必要。
您目前有:
准备:
UPDATE
Execute (100)
ExecuteImmediate(Do):
COMMIT TRAN
当然,没有BEGIN TRAN。 (第一个“执行”执行,BEGIN TRAN消失了)
我认为你想要的(原定的)就是这个。忘掉'做':
准备:
BEGIN TRAN
UPDATE
COMMIT TRAN
执行(100)
然后将其更改为:
BEGIN TRAN
INSERT
UPDATE
COMMIT TRAN
执行(100)
你的$ update和$ insert会让你感到困惑(你正在执行一个多语句批处理,对吧?在准备批处理中间不是一个孤立的单个命令)。如果你摆脱它们,并考虑$ execute [你在批处理中准备的任何东西],它可能会帮助你更好地理解这个问题。
在完成上述所有操作之前,不要形成结论。
阅读BEGIN / COMMIT TRAN。
最后,究竟什么是“END TRAN
”?我不认为您发布的代码块是真实的。
答案 1 :(得分:0)
事实证明,DBI的prepare
方法在各种数据库驱动程序中并不是可移植的,如here所述。对于Sybase驱动程序,prepare
很可能无法正常工作。一种说法是,在运行prepare
之后,变量$insert->{NUM_OF_FIELDS}
未定义。
要解决此问题,请执行以下操作之一:
1)不要做任何准备。只需在文本字符串中动态构造语句并运行$dbh->do($stmt)
或
2)在运行finish
之前,对所有未完成的语句句柄(在该数据库句柄下)运行COMMIT TRAN
。我个人更喜欢这种方式。
答案 2 :(得分:0)
不要动态创建SQL,这很危险(sql注入)。
您应该能够准备多个插入/更新,并且您指向DBI文档的链接并不表示您不能,它说某些驱动程序可能无法告诉您有关仅准备的语句的详细信息。
我将一个有错误的示例发布到dbi-users列表中以便注释,因为DBD :: Sybase维护者在那里挂起(参见dbi.perl.org)。