【问题标题】:How to access database data when exception occur?发生异常时如何访问数据库数据?
【发布时间】:2018-04-02 12:36:07
【问题描述】:

我有下一个代码:

my $savepoint =  $c->db->txn_scope_guard;
return $self->render( 'subnet/create',  error => [ create => $@ ],
    servers =>  $self->rows( 'Server' )->lookup,
) unless $subnet =  eval{ $self->rows( 'Subnet' )->create( $subnet ) };
$savepoint->commit;

这里的 rows 是 Mojolicious 助手,它提供对数据的访问。

sub model {
    my( $c, $table_name ) =  (shift,shift);

    return $c->db->resultset( $table_name );
}

->db也是帮手:

sub db { return $schema
    //=  DBIx::Class::Schema->connect( $DB->{ DSN },  @$DB{ qw/ USER PASS / },  {
        AutoCommit => 1,
        RaiseError => 1,
        quote_char => '"',
    })
});

当我创建$subnet 并发生唯一约束时(这里不管发生哪个约束,实际上是在任何异常的情况下)我得到了错误:

DBIx::Class::Storage::DBI::_dbh_execute(): DBI Exception: DBD::Pg::st execute failed: ERROR:  current transaction is aborted, commands ignored until end of transaction block [for Statement "SELECT "me"."id", "me"."hostname" FROM "servers" "me" ORDER BY hostname"] at ...

这是当我用eval{ ... } 捕获异常时,当前事务被中止,我不能做$self->rows( 'Server' )->lookup

有没有办法在异常发生后访问服务器数据?

【问题讨论】:

  • 为什么不在创建前进行查找?
  • 因为当用户POST他的选择时我不需要查找数据。仅在呈现表单 subnet/create 时才需要查找。

标签: perl dbi dbix-class


【解决方案1】:

似乎我找到了答案,因为更仔细地阅读错误消息:

...在事务块结束之前忽略命令

所以我在异常发生时强制结束事务块:

$c->db->txn_rollback;

代码:

my $savepoint =  $c->db->txn_scope_guard;
unless( $subnet =  eval{ $self->rows( 'Subnet' )->create( $subnet ) } ) {
    my $e = $@; # $@ may be changed before `create => $@`
    undef $savepoint; # Or the same: $c->db->txn_rollback;     
    return $self->render( 'subnet/create',  error => [ create => $e ],
        servers =>  $self->rows( 'Server' )->lookup,
    );
}
$savepoint->commit;

【讨论】:

  • 您应该添加对该引用的引用,以便其他人可以阅读其上下文。
  • 您应该立即将 $@ 保存在除非块中的其他变量中;如果你把其他代码放在第一位,它可能最终会被清除或更改
  • 谢谢,错过了。
  • 这是Try::Tiny 可以帮助您的情况,因为它可以做到$@-save 等。
猜你喜欢
  • 2012-11-28
  • 2013-04-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-11-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多