1

是否必须首选这两种方法中的一种,还是只是口味问题?

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

my $db = 'sqlite_db';

####################   A   ####################

sub get_database_handle {
    my ( $db ) = @_;
    my $dbh;
    eval {
        $dbh = DBI->connect( "DBI:SQLite:$db", '', '', {...} )
        or die DBI->errstr;
    };
    if ( $@ ) {
        print $@;
        return;
    }
    return $dbh;
}

DATABASES: while ( 1 ) {
    # choose a database from a list of databases
    # ...
    my $dbh = get_database_handle( $db );
    next DATABASES if not defined $dbh;
    # ...
    # do something with the database
}

####################   B   ####################

sub get_database_handle {
    my ( $db ) = @_;
    my $dbh = DBI->connect( "DBI:SQLite:$db", '', '', {...} ) 
    or die DBI->errstr;
    return $dbh;
}

DATABASES: while ( 1 ) {
    # choose a database from a list of databases
    # ...
    my $dbh;
    eval { $dbh = get_database_handle( $db ); };
    if ( $@ ) {
        print $@;
        next DATABASES;
    }
    # ...
    # do something with the database
}
4

3 回答 3

3

为什么要评估?当您无法获得数据库句柄时,您会怎么做?

至少,子例程应该返回一个数据库句柄或者死掉,所以那里没有 eval。

如果在出现数据库错误时您确实有工作要做,那么在子例程之外进行 eval 。不需要仅围绕子例程,可以根据您的错误处理逻辑进行更广泛的范围。

但是,如果您只想终止程序并打印错误,那么就让异常冒泡。

于 2012-09-28T07:30:00.837 回答
2

这取决于在项目的其余部分中处理错误的首选方式。

  • 如果您打算使用异常,请让您的函数抛出它们。

  • 如果您要通过条件手动处理错误,请不要抛出(eval inside)。

我自己更喜欢例外。它们很响亮(你知道有些东西坏了!),加上通过Carp::confess/的堆栈跟踪,Carp::longmess并且$SIG{__DIE__}在大型代码库的情况下是一个很好的奖励。

这是一个(不)成功的故事。一两个月前,我们推出了损坏的代码,由于未经检查的 DB 处理函数的返回值而默默地损坏了数据。它生产了一天。恢复数据是一个痛苦的世界。

于 2012-09-28T08:08:35.757 回答
2

RaiseError => 1如果您的代码看起来像那样,那么使用它真的没有任何意义。如果您想保留该代码布局,请RaiseError => 0改用。(您以后可以随时使用 $dbh->{RaiseError} = 1;` 打开它。)

sub get_database_handle {
    my ( $db ) = @_;
    return DBI->connect("DBI:SQLite:$db", '', '', {
        ...
        RaiseError => 0,
        PrintError => 1,
    });
}

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

    ...
}

也就是说,我建议您继续使用RaiseError => 1,但改为更改代码布局。具体来说,您应该扩大评估的范围。

sub get_database_handle {
    my ( $db ) = @_;
    return DBI->connect("DBI:SQLite:$db", '', '', {
        ...
        RaiseError => 1,
        PrintError => 0,
    });
}

for my $db ( ... ) {
    if (!eval {    
        my $dbh = get_database_handle( $db );

        ...

        1  # No exception
    }) {
        warn("Error processing database $db: $@");
    }
}

这将捕获任何错误,而不仅仅是数据库连接错误。

于 2012-09-28T08:13:52.437 回答