【问题标题】:perl eval block throwing execptions without errorperl eval 块抛出 execptions 没有错误
【发布时间】:2017-06-13 12:40:16
【问题描述】:

我正在尝试将一些 DBIX 事务置于 eval 块下,以便在中间出现问题时进行所有事务或不进行任何事务。

我已经完成了几笔这样的交易,但都没有给我带来问题。只有一个:

我构建交易的方式相当棘手,而且,就其价值而言,这些确实有效。如果你愿意,我可以发布那段代码,但也许 eval 块就足够了:

    eval {
      for (my $sub = 0; $sub < $neuroexam_index; $sub++){
        $transactions{neuroexams}{$sub}->insert;
      }
    } or die $!;

问题是 eval 在我的控制台中显示错误 ([error] Caught exception in pbitdb::Controller::Subjects-&gt;add "Died at /home/lioneluranl/svn/pbitdb/pbitdb/script/../lib/pbitdb/Controller/Subjects.pm line 411."),但实际上执行了插入操作。为什么会这样?

【问题讨论】:

  • “如果中间出现问题,要么进行所有事务,要么不进行任何事务” eval 块不会像数据库事务那样运行,如果这就是你的话重新希望。如果后面的调用失败,任何对insert 的调用不会导致异常,则不会回滚。此外,看起来$transactions{neuroexams} 应该是一个 array 引用而不是哈希引用。
  • eval { ... } or do { ... }; 的问题在于它可能会转到do,因为eval 中的代码返回错误(可能是合法的),ikegami 的帖子解决了这个问题。另一种方法是显式测试错误eval { }; if ($@) { ... };,在这种情况下返回无关紧要(它不决定它)。
  • @borodin 这很有趣,因为这意味着我对整个 eval 的理解是错误的。我实际上是从另一个正在工作的催化剂应用程序中已经在工作的代码块中获取这个想法的,它的实现方式如上,关于该实现的文档明确表示预期的行为是创建“全有或全无”之类的东西。如果我在子例程中进行事务处理,然后对子例程进行评估以进行更改,会有什么不同吗?
  • @LionelUranLandaburu:在包括 Perl 在内的绝大多数语言中,没有任何东西可以让您自动倒回从特定时间点开始执行的所有操作。 SQL 具有事务 的概念,它正是这样做的,但仅与数据库中的数据相关。显然,Perl 程序可能采取的行动可能会更远,包括全球互联网上的所有系统,并且该程序可能由多个异步线程组成,因此通常无法完成。
  • @LionelUranLandaburu: eval 简单地捕获可能会终止程序的致命错误,并让您有机会编写处理错误的代码。如果您可以编写代码来“撤消”eval 块在失败之前的操作,那么它可以在出错的情况下执行。但不会自动发生任何事情。

标签: perl eval catalyst dbix-class


【解决方案1】:
eval {
  for (my $sub = 0; $sub < $neuroexam_index; $sub++){
    $transactions{neuroexams}{$sub}->insert;
  }
  1;  # No exception.
}
  or do {
    # ... Perform rollback here ...
    die("[error] Caught exception in pbitdb::Controller::Subjects->add: $@");
  };

if (!eval {
  for (my $sub = 0; $sub < $neuroexam_index; $sub++){
    $transactions{neuroexams}{$sub}->insert;
  }
  1;  # No exception.
}) {
  # ... Perform rollback here ...
  die("[error] Caught exception in pbitdb::Controller::Subjects->add: $@");
}

三个变化:

  • 添加1; 是为了确保在没有异常情况下返回真值,以确保不评估or 的RHS。
  • $@ 中发现捕获的异常,而不是在$!。 ($! 映射到 errno,由 C 库调用和系统调用设置的错误代码。)
  • 捕获异常以简单地重新抛出它没用。您似乎想捕获异常以包装异常消息,但您没有这样做。您还提到了数据库事务,所以我假设您想在异常时执行回滚。

【讨论】:

  • 感谢您的提示 :) 。现在,添加“1”不会强制评估忽略上面是否发生错误?刚刚测试了一下,现在和1都没有抛出异常,但是去掉它会导致再次抛出异常。这安全吗?
  • 如果块中较早发生异常,它将不会到达1
  • @ikegami 纯粹出于好奇,与简单的if() 相比,以or do 方式执行此操作有什么好处吗?
  • @stevieb,它们是等价的。
  • @stevieb 很好奇,我发现or do 是最简单和最干净的方式。但这正是它需要 1 .... eh 的原因
猜你喜欢
  • 2023-04-08
  • 1970-01-01
  • 1970-01-01
  • 2014-05-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-04-08
相关资源
最近更新 更多