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.
War es hilfreich?

Lösung

Wenn dies aus irgendeinem Grund fehlschlägt, werden die meisten $ dbh Methoden entweder:

  • (wenn RaiseError option ist auf 0 gesetzt) return undef
  • (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.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top