2010-04-13 97 views
8

我玩弄错误处理,并得到一个小问题。 我使用DBI模块连接数据库。Perl:捕获错误无死亡

我通过使用一个调用错误的子例程来完成自己的错误处理。

我能听到我自己的模具,进行处理得很好,但,当我的数据库连接失败,DBI模块显然打印出它自己的芯片:

DBI connect(...) failed: ORA-12154: TNS:could not resolve the connect identifier specified (DBD ERROR: OCIServerAttach) at ...

我怎么会去追赶呢?

我尝试使用$SIG{__DIE__}像这样:

local $SIG{__DIE__} = sub { 
    my $e = shift; 
    print "Error: " .$e; 
}; 

这是我的主要文件的底部,在这个文件我也调用connect子程序可用我自己的模块中。我也试着把这段代码放在我的模块的底部,但它仍然在它的前面打印出错误,而不是在其前面没有

Error:

回答

3

好了,找到了解决办法,显然我需要__WARN__,而不是__DIE__和这段代码是在文件的顶部需要,在抛出的错误之前,不像比如我读说:)

+3

这是正确的,这是一个警告,而不是一个死亡,并且必须首先安装处理程序。如果将其包装在'BEGIN {}'中,可以将它安装在任何模块中。 – Ether 2010-04-13 14:56:12

+0

也读了,谢谢你的验证。 – Pmarcoen 2010-04-13 15:33:30

2

DBI中有很多开关,如PrintError,RaiseError等,您可以调整它们。 见http://search.cpan.org/perldoc?DBI

+0

嗯,是不是有更通用的解决方案?这样我可以用1个函数捕获所有其他错误。我可能会使用很多有很多方法来输出错误的模块,我想独立于此。 – Pmarcoen 2010-04-13 11:18:01

+0

DBI也有一个HandleError方法。或者,如果您将PrintError设置为false,则RaiseError为true,则应调用您的(Pmarcoen's)错误处理。 – runrig 2010-04-13 14:44:32

0

这不像通用模具捕捉器那样通用,而是专门针对DBI错误处理,我们实际上有我们自己的模块提供数据库调用的包装;并且模块的一个功能是在每个DBI调用周围包装eval(取决于标志)。

这使我们能够对数据访问级别进行自定义错误处理,例如查询重试,统计,自动故障转移等 - 对代码的其余部分都是透明的。

8

DBI connect(...) failed: ORA-12154: TNS:could not resolve the connect identifier specified (DBD ERROR: OCIServerAttach) at ...

How would I go about catching this ?

要捕获并处理这种级别的错误,请以块形式“eval {...}”使用eval。这将捕获子代码中发生的任何死亡。如果eval块中的代码死亡,它将设置$ @并且该块将返回false。如果代码没有死掉,$ @将被设置为''。

通过SIG {WARN}和SIG {DIE}处理信号很麻烦,因为它们是全球性的,还有竞争条件需要考虑(如果我在处理不同信号时收到信号会发生什么?基于信号的计算的传统问题)。您可能正在编写单线程代码,因此您不担心多个事件调用并发问题,但用户需要考虑(也许他会在尝试打开DBI连接时发送SIGKILL )

在这种特定情况下,您正在使用DBI。使用DBI,您可以控制发生错误时发生的情况,如果它发生死亡,发出警告或无法正常运行并等待您检查返回状态。

以下是使用eval {...}的基本示例。

my $dbh = eval { DBI->connect(@args) }; 
if ([email protected]) 
{ 
    #DBI->connect threw an error via die 
    if ([email protected] =~ m/ORA-12154/i) 
    { 
     #handle this error, so I can clean up and continue 
    } 
    elsif ([email protected] =~ m/SOME \s* other \s* ERROR \s+ string/ix) 
    { 
     #I can't handle this error, but I can translate it 
     die "our internal error code #7"; 
    } 
    else 
    { 
     die [email protected]; #re-throw the die 
    } 
} 

以这种方式使用eval有一些小问题,与全局范围$ @有关。 Try::Tiny cpan页面有一个很好的解释。 Try :: Tiny处理最小的Try/catch块设置,并处理本地化$ @和处理其他边缘情况。

+0

这就是我最初的方式,但eval并没有收到我想要报告的警告。因此,我必须使用SIG {WARN}。 – Pmarcoen 2010-04-14 07:45:44

2

SIG{__DIE__}块包含此:

### Check if exceptions being caught. 
return if $^S; 

这将防止您的处理程序从上一个eval块内生成模具基于异常的代码中使用了。