重新启动在PostgreSQL中失败的事务

3

所谓事务,是指将多个SQL语句封装在一个(例如)begin isolation level serializable块中。并发事务可能会使此事务失败,即回滚。

如何在PostgreSQL中重新启动失败的事务?


1
你必须注意这种事件,并准备好从客户端重新开始相同的事务,以防在失败后该操作仍然有效。 - Kouber Saparev
但是当交易失败时,所有客户端都会收到通知吗?我正在使用node-postgres(node.js),但我不确定事务失败是否会抛出异常。 - ehmicky
1
pg-promise 支持嵌套事务,在嵌套层次上,它们成为保存点(save points),您可以使用它们来恢复您的事务。 - vitaly-t
2个回答

4
你需要使用客户端特定的机制来检测事务中的错误。当你看到错误时,必须回滚事务重新发起整个事务。你不能只重新执行最近的部分1ROLLBACK是必需的;如果你不这样做,那么该连接上的任何进一步操作都会失败,并显示“事务中止”错误。
大多数客户端驱动程序(在支持它们的语言中)抛出异常以指示 SQL 错误,或者期望您在每个数据库操作后检查错误代码,通过检查函数返回代码或调用特殊函数来检查错误。 node-postgres 是异步和非阻塞的,因此不太可能抛出异常;你应该寻找一个函数,让你查询会话中最后一个操作的结果 SQLSTATE 和客户端驱动程序的错误状态。

node-postgres 似乎没有充足的文档资料,所以您最好查看 node-postgres 的源代码或找到其他人如何处理此类问题的示例。我相信您会找到检查会话错误状态的函数。您需要寻找的是一个函数来获取连接上最后一次操作的 SQLSTATE

值得注意的是,可以发布一个专门关注如何检测和处理 node-postgres 中错误的问题。


1实际上,SAVEPOINTROLLBACK TO SAVEPOINT可以让您做到这一点,但它们不能帮助处理序列化错误。


这正是我想要的答案。非常感谢! - ehmicky

1

这个答案是在3年后添加的,以考虑到此期间的变化。尽管原始答案仍然有效,但这个答案展示了如何使用当时不可用的正确工具来轻松完成。


使用pg-promise很容易实现,它支持任意嵌套级别的嵌套事务。请参见嵌套事务,其中解释了顶层事务由标准的BEGIN->COMMIT/ROLLBACK表示,而所有嵌套事务都会自动变成SAVEPOINT
db.tx(t => {
    // BEGIN
    // top-level changes cannot be restarted:
    return t.any('UPDATE users SET name=$1 WHERE id=$2', ['Mike', 123])
        .then(() => {
            return t.tx(t1 => {
                // SAVEPOINT
                return t1.none('INSERT log(event) VALUES($1)', 'entry');
            })
                .catch(error => {
                    // ROLLBACK TO SAVEPOINT executed
                    return t.none('UPDATE log SET event = $1');
                });
        });
})
    .then(data => {
        // success, COMMIT executed
    })
    .catch(error => {
        // error, ROLLBACK executed
    });

在上面的示例中,我们对顶层进行了UPDATE操作,由于这个原因不能重新启动。然后我们进行了嵌套事务/保存点,其中包括一个INSERT,如果失败,则再次替换为顶层的UPDATE
这样,即使我们的SAVEPOINT失败,我们仍然可以成功完成顶层事务。
如果您想能够重新启动整个事务,只需将整个内容包装到子事务中,然后在主事务内多次运行即可。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接