Perl DBI 何时关闭准备好的语句

Posted

技术标签:

【中文标题】Perl DBI 何时关闭准备好的语句【英文标题】:Perl DBI when to close prepared statements 【发布时间】:2014-04-17 09:06:01 【问题描述】:

我有一个奇怪的问题。在我的开发计算机上,我遇到了错误。但是在实时系统上不会发生错误。如果我在 dev 上解决问题,则修复会导致生产问题。

这与我何时关闭准备好的语句有关。在生产中,我必须在每次获取后调用完成。如果我在我的开发系统上执行此操作,那么该语句的下一次执行将返回 undef,并且 $dbh->errstr 或 $DBI::errstr 中没有任何内容。

任何想法从哪里开始?

这是一个简单的测试:

#!/usr/bin/perl

use strict;
use warnings;

use DBI;
use DateTime;
use DateTime::Format::Strptime;
use Data::Dumper;

# Debug flag.
my $debug = 1;

#helper
sub getLoggingTime 

    my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst)=localtime(time);
    my $nice_timestamp = sprintf ( "%04d/%02d/%02d %02d:%02d:%02d",
                               $year+1900,$mon+1,$mday,$hour,$min,$sec);
    return $nice_timestamp;


# Debug function.
sub dbg  if (! $debug)  return ; my $str = getLoggingTime() . " " . shift ; print STDERR $str 

# These are *the* date and time formats we use.
my $dateFormat = new DateTime::Format::Strptime('pattern' => '%F', 'locale' => 'en_NZ',             'time_zone' => 'Pacific/Auckland');
my $timeFormat = new DateTime::Format::Strptime('pattern' => '%T', 'locale' => 'en_NZ', 'time_zone' => 'Pacific/Auckland');

# Connect to the database.
my $dbconnect = *****removed**** || die 'No dbi_connection configured.';
my $dbusername = *****removed**** || die 'No dbi_username configured.';
my $dbpassword = *****removed**** || die 'No dbi_password configured.';

my $dbh = DBI->connect ($dbconnect, $dbusername, $dbpassword,  RaiseError => 1, PrintError => 1, AutoCommit => 1 ) ||
    die 'Cannot connect to database. ' . DBI::errstr;
my $test_sth = $dbh->prepare('
    SELECT 
        ? as teststring, 
        GETDATE() as testdate
    ') || die 'Cannot prepare franchise name statement: ' . ($dbh->errstr ||$DBI::errstr || "")  . "\n";


##Attempt One
$test_sth->execute("Test string") || die "Could not execute test statement: " . ($dbh->errstr ||$DBI::errstr || "") . "\n";

my $result = $test_sth->fetchrow_hashref()
|| die "Cannot get result: " . ($dbh->errstr ||$DBI::errstr || "") . "\n";
$test_sth->finish();

my $testString = $result->'teststring';
my $testDate =  $result->'testdate';

dbg("testString = $testString, testDate = $testDate\n");


##Attempt Two 
$test_sth->execute("Test string") || die "Could not execute test statement: " . ($dbh->errstr ||$DBI::errstr || "") . "\n";

$result = $test_sth->fetchrow_hashref()
|| die "Cannot get result: " . ($dbh->errstr ||$DBI::errstr || "") . "\n";
$test_sth->finish();

$testString = $result->'teststring';
$testDate =  $result->'testdate';

dbg("testString = $testString, testDate = $testDate\n");

$dbh->disconnect();
1;

在开发中我得到:

perl dbiTest.pl 2014/03/13 11:15:51 testString = 测试字符串,testDate = 2014 年 3 月 13 日上午 11:15 无法执行测试语句:

我得到的产品:

dbiTest.pl 2014/03/13 11:17:20 testString = 测试字符串,testDate = 2014 年 3 月 13 日上午 11:17 2014/03/13 11:17:20 testString = 测试字符串,testDate = 2014 年 3 月 13 日上午 11:17

如果我评论第一个 $test_sth->finish(); 在开发中我得到:

perl dbiTest.pl 2014/03/13 11:24:44 testString = 测试字符串,testDate = 2014 年 3 月 13 日上午 11:24 2014/03/13 11:24:44 testString = 测试字符串,testDate = 2014 年 3 月 13 日上午 11:24 在产品上我得到: perl dbiTest.pl 2014/03/13 11:18:06 testString = 测试字符串,testDate = 2014 年 3 月 13 日上午 11:18 DBD::Sybase::st 执行失败:OpenClient 消息:LAYER = (0) ORIGIN = (0) SEVERITY = (78) NUMBER = (51) 消息字符串:尝试启动新的 Adaptive Server 操作,但结果未决 DBD::Sybase::st 执行失败:OpenClient 消息:LAYER = (0) ORIGIN = (0) SEVERITY = (78) NUMBER = (51) 消息字符串:尝试启动新的 Adaptive Server 操作,结果未决

更新: 设置$dbh->syb_flush_finish = 1; 允许开发系统运行完成而不中断。 这确实解决了我的问题,但没有解释发生了什么。

【问题讨论】:

开发机器和生产机器上的 perl 版本有区别吗?我已经看到了具有不同版本行为的这种行为。 是的,prod 是 perl v5.10.1,dev 是 v5.14.2 很有可能是版本不同导致了这个错误 这只是一个风格建议,但不是建立你的时间戳,而是可以使用 use Time::Piece; print localtime->strftime("%Y/%m/%d %H:%M:%S"); Time::Piece 自 5.8 以来一直在 perl 核心中 也许 DBD::Sybase 在某些时候对完成应该如何工作感到困惑。您可以尝试在初始提取后读取选择(直到 fetchrow 返回 null)而不是 finish 【参考方案1】:

您的DBD::Sysbase 版本已经过时了。根据changelog,在 v1.01 中添加了一个修复程序(早在 2003 年 9 月就发布了!)

finish() 语句自动处理,如果它们在所有行被提取之前被重新执行。

在 v1.06(2005 年 8 月)中有另一个修复,因为 finish 有时无法清理关联的数据库句柄。自 v1.00 以来发生了很多很多的变化,所以请升级到最新版本并放弃对 finish 的调用。

【讨论】:

以上是关于Perl DBI 何时关闭准备好的语句的主要内容,如果未能解决你的问题,请参考以下文章

Perl 执行 DBI 循环执行

Perl DBI - 使用多个语句运行 SQL 脚本

Perl DBI 语句句柄和错误处理

Perl DBI - 获取事务中每个语句影响的记录

当跟踪中的语句返回 1 时,为啥 perl DBI 返回 0 行

准备好的语句何时失败?