Вопрос

Этот вопрос относится к этому комментарию Икегами:

[...] 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) немедленно выйти из сценария («умереть»), указав причину ошибки в сообщении о выходе.

Ключевым моментом здесь является то, что вам решать, как обрабатывать ошибки.Если хотите, вы можете, например, просто игнорировать их (следующее, очевидно, будет работать с RaiseError установлен в 0 только):

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

В этом фрагменте (скопированном из ответа @ikegami, который вы упомянули в своем вопросе) вы просматриваете некоторый список настроек для подключения к БД;если какое-то соединение дает вам undef, вы просто переходите к другому и ничего не делаете с ошибкой.

Однако обычно при возникновении ошибки вам нужно сделать больше, чем просто «следующий шаг», но опять же, у вас есть два варианта:либо проверьте каждый $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');

(как or части будут выполняться только в том случае, если их соответствующие «левые части» оцениваются как false в логическом контексте).

…или просто оберните все это в блок «try-catch» Perlish:

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).

И это именно то, что произошло в последней части кода вашего исходного вопроса.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top