DBI: raiseerror in eval



这个问题指的是Ikegami的评论:

[...] 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):

for my $db ( ... ) {
my $dbh = get_database_handle( $db )
or next;
...
}

在这个片段中(复制自你在问题中提到的@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时,才会执行or部分)

或者把所有这些都打包到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上调用方法)。

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

相关内容

  • 没有找到相关文章

最新更新