3

注意:RaiseError 设置为 false。

$dbh->begin_work;
$dbh->do("..."); # sql1, ok
$dbh->do("..."); # sql2, fails (e.g. syntax error)
$dbh->do("..."); # sql3, ok
$dbh->commit;

这将导致 sql1 和 sql3 的效果被提交,这是不可取的,因为在这种情况下,我希望 SQL 语句一起成功/失败。目前我的解决方法是这样的:

eval {
    local $dbh->{RaiseError} = 1;
    $dbh->begin_work;
    $dbh->do("..."); # sql1, ok
    $dbh->do("..."); # sql2, fails (e.g. syntax error)
    $dbh->do("..."); # sql3, ok
    $dbh->commit;
};
$dbh->rollback if $@; # needed, RaiseError does not automatically rollback

但我不太喜欢它。还有其他更简单的选择吗?我更喜欢 Postgres 的行为:

$dbh->begin_work;
$dbh->do("..."); # sql1, ok
$dbh->do("..."); # sql2, fails (e.g. syntax error)
$dbh->do("..."); # sql3, ok but fail because transaction status is now aborted
$dbh->commit;    # becomes rollback
4

1 回答 1

2

一种选择是围绕 DBD::SQLite 的 db 句柄实现一个包装器,它跟踪错误状态并在错误后忽略命令,就像 Pg 一样。我没有看到任何迹象表明 DBD::SQLite 可以做到这一点,或者 SQLite 本身就支持这种模式,因此您可能必须在包装器中实现它。


我最初认为您可能想要ON CONFLICT ROLLBACK而不是 default ON CONFLICT ABORT,但更多阅读表明它不会完成这项工作。

您可以设置冲突和错误处理解决策略。文档建议它在表或每个语句级别工作,但语法映射显示它实际上是逐列的,适用于 NOT NULL 约束之类的东西

我不确定ON CONFLICT ROLLBACK是否会使 tx 无效,也不确定它是否适用于所有错误。文档有点不清楚。它可能会回滚并进入下一条语句的自动提交模式,这同样糟糕。

于 2012-08-22T13:31:28.260 回答