9

我正在玩错误处理并遇到了一个小问题。我使用 DBI 模块连接数据库。

我使用调用错误的子例程来进行自己的错误处理。

我可以抓住自己的模具并很好地处理它们,但是当我的数据库连接失败时,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;
};

这是我的主文件的底部,在这个文件中,我还调用了我自己的模块中可用的连接子例程。我还尝试将这段代码放在模块的底部,但它仍然打印错误而没有

错误:

在它面前。

4

5 回答 5

9

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

我要怎么抓到这个?

要捕获和处理这种级别的错误,请以块形式使用 eval,“eval { ... }”。这将捕获子代码中发生的任何死亡。如果 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 块设置并处理本地化 $@ 和处理其他边缘情况。

于 2010-04-14T07:11:28.713 回答
3

将其包含在您的SIG{__DIE__}块中:

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

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

于 2010-04-14T13:30:04.803 回答
3

好的,找到了解决方案,显然我需要__WARN__而不是__DIE__并且这段代码需要在文件顶部,在引发错误之前,不像我读到的例子:)

于 2010-04-13T11:27:24.267 回答
2

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

于 2010-04-13T11:03:27.973 回答
0

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

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

于 2010-04-13T13:47:58.967 回答