DBI:raiseerror bei der Bewertung
-
11-12-2019 - |
Frage
Diese Frage bezieht sich auf diesen Kommentar von Ikegami:
[...] But if you're going to put an eval around every statement, just use RaiseError => 0. [...]
darin Thread.
Was gewinne ich, wenn ich setze RaiseError
zu 0
in solchen Situationen?
#!/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: $@" };
Ausgabe:
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.
Lösung
Wenn dies aus irgendeinem Grund fehlschlägt, werden die meisten $ dbh Methoden entweder:
- (wenn
RaiseError
option ist auf 0 gesetzt) returnundef
- (wenn
RaiseError
option ist auf 1 gesetzt) Beenden Sie das Skript sofort ('die') mit dem Fehlergrund, der als Exit-Nachricht angegeben wird.
Der entscheidende Punkt hier ist, dass es an Ihnen liegt, wie Sie die Fehler verarbeiten.Wenn Sie möchten, können Sie sie zum Beispiel einfach ignorieren (das Folgende funktioniert natürlich mit RaiseError
setzen auf 0
nur):
for my $db ( ... ) {
my $dbh = get_database_handle( $db )
or next;
...
}
In diesem Ausschnitt (kopiert aus @ ikegamis Antwort, die Sie in Ihrer Frage erwähnt haben) durchlaufen Sie eine Liste von Einstellungen für die DB-Verbindung;wenn eine Verbindung Ihnen eine gibt undef
, du gehst einfach zu einem anderen und machst nichts mit Fehlern.
Normalerweise müssen Sie jedoch mehr tun, als nur zu 'Nexten', wenn ein Fehler auftritt - aber andererseits haben Sie zwei Möglichkeiten:entweder überprüfen jeder $dbh
-verwandte Aussage mit so etwas:
$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');
(als or
teile werden nur ausgeführt, wenn ihre entsprechenden 'linken Teile' zu folgendem Ergebnis führen false
im booleschen Kontext).
...oder wickeln Sie das alles einfach in einen perlischen 'Try-Catch' -Block ein:
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($@);
}
Was ist zu wählen, es liegt an dir:es ist eine häufige Entscheidung zwischen 'Fehlern in Rückgabeanweisungen' (außer dass Sie zum Abrufen eines tatsächlichen Fehlers das $ dbh-Objekt fragen müssen) und Ausnahmen.
Aber unter dem Strich können Sie nicht nur das schreiben:
$sth = $dbh->do_something('that_can_result_in_error');
$sth->do_something('else');
...wenn du gesetzt hast RaiseError
zu 0
.In diesem Fall stirbt das Skript nicht, $sth
wird eine zugewiesen undef
, und Sie erhalten einen 'derivativen' Fehler (da Sie keine Methode aufrufen können undef
).
Und genau das ist im letzten Teil des Codes in Ihrer ursprünglichen Frage passiert.