Perl DBI:评估中的raiseerror

Perl DBI:评估中的raiseerror,perl,exception-handling,eval,dbi,raiseerror,Perl,Exception Handling,Eval,Dbi,Raiseerror,这个问题涉及池上的评论: [...] But if you're going to put an eval around every statement, just use RaiseError => 0. [...] 在这方面 在这种情况下,如果我将RaiseError设置为0,我会得到什么 #!/usr/bin/env perl use warnings; use 5.10.1; use DBI; my $db = 'my_test_sqlite_db.sqlite'; open

这个问题涉及池上的评论:

[...] But if you're going to put an eval around every statement, just use RaiseError => 0. [...]
在这方面

在这种情况下,如果我将
RaiseError
设置为
0
,我会得到什么

#!/usr/bin/env perl
use warnings;
use 5.10.1;
use DBI;

my $db = 'my_test_sqlite_db.sqlite';
open my $fh, '>', $db or die $!;
close $fh or die $!;

my ( $dbh, $sth );
eval {
    $dbh = DBI->connect( "DBI:SQLite:dbname=$db", "", "", {} );
};
if ( $@ ) { print $@ };

my $table = 'my_sqlite_table';

say   "RaiseError = 1";
say   "PrintError = 0";
$dbh->{RaiseError} = 1;
$dbh->{PrintError} = 0;
eval {
    $sth = $dbh->prepare( "SELECT * FROM $table" );
    $sth->execute();
};
if ( $@ ) { print "ERROR: $@" };

say "\nRaiseError = 0";
say   "PrintError = 1";
$dbh->{RaiseError} = 0;
$dbh->{PrintError} = 1;
eval {
    $sth = $dbh->prepare( "SELECT * FROM $table" );
    $sth->execute();
};
if ( $@ ) { print "ERROR: $@" };

say "\nRaiseError = 0";
say   "PrintError = 0";
$dbh->{RaiseError} = 0;
$dbh->{PrintError} = 0;
eval {
    $sth = $dbh->prepare( "SELECT * FROM $table" );
    $sth->execute();
};
if ( $@ ) { print "ERROR: $@" };
输出:

RaiseError = 1
PrintError = 0
ERROR: DBD::SQLite::db prepare failed: no such table: my_sqlite_table at ./perl2.pl line 23.

RaiseError = 0
PrintError = 1
DBD::SQLite::db prepare failed: no such table: my_sqlite_table at ./perl2.pl line 33.
ERROR: Can't call method "execute" on an undefined value at ./perl2.pl line 34.

RaiseError = 0
PrintError = 0
ERROR: Can't call method "execute" on an undefined value at ./perl2.pl line 44.

如果由于某些原因失败,大多数$dbh方法将:

  • (如果
    RaiseError
    选项设置为0)返回
    undef
  • (如果
    RaiseError
    选项设置为1),立即退出脚本(“die”),并将错误原因作为退出消息给出
这里的关键是,如何处理错误取决于您。如果愿意,您可以忽略它们,例如(以下内容显然只适用于
RaiseError
设置为
0
):

在这个片段中(复制自您在问题中提到的@ikegami的答案),您循环了一些DB连接设置列表;如果某个连接为您提供了一个
undef
,您只需转到另一个连接,并且不做任何错误处理

但是,通常情况下,当错误发生时,您需要做的不仅仅是“nexting”,而且您还有两个选择:或者使用如下内容检查每个与
$dbh
相关的语句:

$sth = $dbh->prepare('some_params') 
  or process_db_error('In prepare');
...
$res = $sth->execute('another_set_of_params') 
  or process_db_error('In execute');
...
$res->doAnythingElse('something completely different') 
  or process_db_error('In something completely different');
(仅当其对应的“左部分”在布尔上下文中计算为
false
时,才会执行as
部分)

…或者将所有这些都包装到Perlish“try catch”块中:

if (!eval {    
   $sth = $dbh->prepare('some_params');
   ...
   $res = $sth->execute('another_set_of_params');
   ...
   $res->doSomethingElse('something completely different') 
   ...
   1  # No exception
}) {
   process_db_error($@);
}
选择什么,取决于您:这是“返回语句中的错误”和异常之间的共同决定(除了要获取实际错误,您必须询问$dbh对象)

但底线是你不能只写这个:

$sth = $dbh->do_something('that_can_result_in_error');
$sth->do_something('else');
。。。如果您确实将
RaiseError
设置为
0
。在这种情况下,脚本不会消亡,
$sth
将被分配一个
undef
,您将得到一个“派生”错误(因为您不能在
undef
上调用方法)


这正是您最初问题中代码的最后一部分所发生的情况。

这是预期的行为-DBI返回undef(当异常被关闭时);Perl不知道如何处理这个未定义的值,因此死亡。问题是什么?
$sth = $dbh->do_something('that_can_result_in_error');
$sth->do_something('else');