Perl:捕获错误而不死

发布于 2024-08-28 11:38:43 字数 547 浏览 12 评论 0原文

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

我通过使用在出现错误时调用的子例程来进行自己的错误处理。

我可以捕获自己的模具并很好地处理它们,但是当我的数据库连接失败时,DBI 模块显然会打印出它自己的模具:

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

我将如何捕获这个?

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

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

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

错误:

在它前面。

I'm playing around with error handling and got a little problem.
I connect with a database using the DBI module.

I do my own error handling by using a subroutine that I call upon an error.

I can catch my own dies and handle them just fine but when my database connection fails, the DBI module apparently prints out it's own die :

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

How would I go about catching this ?

I tried using $SIG{__DIE__} like so :

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

This is on the bottom of my main file, in this file I also call the connect subroutine that is available in a module of my own. I also tried putting this piece of code on the bottom of my module but it still prints the error without the

Error:

in front of it.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

谎言 2024-09-04 11:38:43

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

我该如何捕捉这个?

要捕获并处理此级别的错误,请以块形式使用 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 块设置,并处理本地化 $@ 和处理其他边缘情况。

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

How would I go about catching this ?

To catch and handle this level of error, use eval in block form, "eval { ... }". This will catch any die that happens in the sub code. If the code within an eval block dies, it will set $@ and the block will return false. If the code does not die, $@ will be set to ''.

Using signal handling via SIG{WARN} and SIG{DIE} is troublesome since they are global, there are also race conditions to consider (what happens if I get a signal while I'm handling a different signal? etc. The traditional issues of signal based computing). You're probably writing single-threaded code, so you're not worried about concurrency issues of multiple things calling die, but there is the user to consider (maybe he'll send a SIGKILL while you're trying to open the DBI connection)

In this specific case, you are using DBI. With DBI, you can control what happens in the case of error, if it should die, warn, or fail silently and wait for you to check the return status.

Here is a basic example of using 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
    }
}

There are some minor issues with using eval this way, having to do with the global scope of $@. The Try::Tiny cpan page has a great explanation. Try::Tiny handles a minimal Try/catch block setup and handles localizing $@ and handling the other edge cases.

时光瘦了 2024-09-04 11:38:43

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

Okay, found the solution, apparently I needed __WARN__ instead of __DIE__ and this piece of code needed to be in the top of the file, before where the error was thrown, unlike the example I read stated :)

孤单情人 2024-09-04 11:38:43

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

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

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

Include this in your SIG{__DIE__} block:

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

This will prevent your handler from being used on exception-based code that generates a die within an eval block.

新雨望断虹 2024-09-04 11:38:43

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

There are lots of switches in DBI, like PrintError, RaiseError, etc. which you can adjust.
See http://search.cpan.org/perldoc?DBI

挽心 2024-09-04 11:38:43

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

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

This is not as generic as an overall die catcher, but specifically for DBI error handling we actually have our own module providing wrappers around database calls; and one of the module's functionalities is to wrap eval (depending on a flag) around each DBI call.

This allows us to do custom error handling on data access level, such as query retries, statistics, automated failover and more - all transparent to the rest of the code.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文