Perl:捕获错误而不使用die

9
我正在处理与错误处理相关的问题,遇到了一些小问题。我使用DBI模块连接数据库。
我通过使用一个子程序来进行自己的错误处理。
我可以捕获我的自定义die并处理它们,但是当我的数据库连接失败时,DBI模块似乎会打印出自己的die:
DBI connect(...)失败:ORA-12154:TNS:无法解析指定的连接标识符(DBD ERROR:OCIServerAttach)位于...。
我该如何捕捉这个错误?
我尝试使用$SIG{__DIE__},像这样:
local $SIG{__DIE__} = sub {
  my $e = shift;
  print "Error: " .$e;
};

这段代码位于我的主文件底部,我还在该文件中调用了一个属于我自己模块的connect子程序。我也尝试将此代码放在我的模块底部,但它仍然在

错误:

之前打印。

5个回答

9

DBI连接失败:ORA-12154: TNS:无法解析连接标识符(DBD错误: OCIServerAttach)位于...

我该如何捕获这个错误?

要捕获和处理此级别的错误,请使用 eval 块形式,"eval { ... }"。这将捕获子代码中发生的任何 die 错误。如果 eval 块内的代码死亡,它将设置 $@ 并返回 false。如果代码没有死亡,则 $@ 将设置为''。

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

在这种特定情况下,您正在使用 DBI。使用 DBI,您可以控制在出现错误时应该发生什么,是否应该死亡、警告或静默失败并等待您检查返回状态。

这里是使用 eval { ... } 的基本示例。

my $dbh = eval { DBI->connect( @args) };
if ( $@ )
{
    #DBI->connect threw an error via die
    if ($@ =~ m/ORA-12154/i )
    {
        #handle this error, so I can clean up and continue
    }
    elsif ( $@ =~ 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 $@; #re-throw the die
    }
}

使用eval存在一些小问题,与$@的全局作用域有关。 Try::Tiny cpan页面有很好的解释。 Try::Tiny处理最小的Try / catch块设置,并处理本地化$ @和处理其他边缘情况。


这是我一开始的方式,但是 eval 并不能捕获我想要报告的警告。因此,我必须使用 SIG{WARN}。 - Pmarcoen

3

好的,找到了解决方案,显然我需要使用__WARN__而不是__DIE__,并且这段代码需要在文件的顶部,而不是错误抛出的位置之后。与我阅读的示例所述不同 :)


3
没错,这是个警告而不是致命错误,且必须先安装处理器。如果你将其包装在 BEGIN{} 中,可以在任何模块中安装处理器。 - Ether

3

在你的SIG{__DIE__}块中包含以下内容:

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

这将防止您的处理程序用于在eval块内生成die的异常代码。

2

嗯,有没有更通用的解决方案?这样我就可以用一个函数捕获所有其他错误。我可能会使用很多模块,它们有很多输出错误的方式,我希望独立于此。 - Pmarcoen
DBI 还有一个 HandleError 方法。或者,如果将 PrintError 设置为 false,RaiseError 设置为 true,则应调用您(Pmarcoen)的错误处理。 - runrig

0

这不是一个通用的死机捕获器,而是针对DBI错误处理的我们实际上有自己的模块提供包装器来处理数据库调用;其中一个模块的功能是在每个DBI调用周围包装eval(取决于标志)。

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接