[英]Restart a failed transaction in PostgreSQL
By transaction I mean several SQL statements wrapped (for example) in a begin isolation level serializable
block. 通过事务,我的意思是在begin isolation level serializable
块中包含(例如)几个SQL语句。 A concurrent transaction can make this transaction fail, ie rollback. 并发事务可以使此事务失败,即回滚。
How to restart the failed transaction in PostgreSQL? 如何在PostgreSQL中重启失败的事务?
You need to use client-driver specific mechanisms to detect an error in the transaction. 您需要使用特定于客户端驱动程序的机制来检测事务中的错误。 When you see an error you must rollback the transaction and re-issue the entire transaction . 当您看到错误时,您必须回滚事务并重新发出整个事务 。 You can't just re-do the most recent part 1 . 你不能只重新做最新的第1部分。
The ROLLBACK
is required; ROLLBACK
是必需的; if you don't do it, any further operations on that connection fail with a "transaction aborted" error. 如果不这样做,该连接上的任何进一步操作都会因“事务中止”错误而失败。
Most client drivers either throw exceptions (in languages that support them) to indicate SQL errors, or expect you to check for an error code after every database operation, either by checking a function return code, or by calling a special function to check for errors. 大多数客户端驱动程序抛出异常(使用支持它们的语言)来指示SQL错误,或者希望您在每次数据库操作后检查错误代码,方法是检查函数返回代码,或者调用特殊函数来检查错误。 node-postgres
is asynchronous and non-blocking, so it's not especially likely to throw exceptions; node-postgres
是异步和非阻塞的,因此它不太可能抛出异常; you should be looking for a function that lets you query a session for the last operation's resulting SQLSTATE
and client driver error status. 您应该查找一个函数,该函数允许您查询会话以查找最后一个操作导致的SQLSTATE
和客户端驱动程序错误状态。
node-postgres
doesn't seem to have abundant documentation so your best bet may be to examine the source code for node-postgres, or find examples of how other people do this. node-postgres
似乎没有丰富的文档,所以你最好的选择是检查node-postgres的源代码,或找到其他人如何做到这一点的例子。 I expect you'll find functions to check the error state of a session. 我希望你能找到检查会话错误状态的函数。 What you're looking for is a function to get the SQLSTATE
for the last operation on the connection. 您正在寻找的是为连接上的最后一个操作获取SQLSTATE
的函数。
It may be worth posting a question that's focused specifically on how to detect and handle errors in node-postgres. 可能值得发布一个专门针对如何检测和处理node-postgres中的错误的问题。
1 Actually, SAVEPOINT
and ROLLBACK TO SAVEPOINT
let you do exactly that, but they won't help with serialization errors. 1实际上, SAVEPOINT
和ROLLBACK TO SAVEPOINT
让你做到这一点,但它们无法帮助解决序列化错误。
This answer was added 3 years later, to account for changes since. 这个答案在3年后被添加,以说明自那以来的变化。 And even though the original answer is still valid, this answer shows how easy it is to do today with the right tools that weren't available back then. 尽管最初的答案仍然有效,但这个答案表明,今天使用当时无法使用的正确工具是多么容易。
It is easy to do with pg-promise , which supports nested transactions of any nested level. 使用pg-promise很容易,它支持任何嵌套级别的嵌套事务。 See Nested Transactions where it explains that while the top-level transaction is represented by your standard BEGIN
-> COMMIT
/ ROLLBACK
, all nested transactions automatically become SAVEPOINT
. 请参阅嵌套事务 ,其中解释了当顶级事务由标准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
});
In the example above we do an UPDATE
on the top level, which cannot be restarted for that reason. 在上面的示例中,我们在顶层执行UPDATE
,由于这个原因无法重新启动。 And then we do a nested transaction/savepoint, with an INSERT
, which if fails, replaced with an UPDATE
on the top level again. 然后我们使用INSERT
执行嵌套事务/保存点,如果失败,则再次替换为顶层的UPDATE
。
This way, even though our SAVEPOINT
failed, we can still finish our top-level transaction successfully. 这样,即使我们的SAVEPOINT
失败,我们仍然可以成功完成顶级交易。
And if you want to be able to restart the entire transaction, simply wrap the whole thing into a sub-transaction, which you then can re-run inside the main transaction as many times as you want. 如果您希望能够重新启动整个事务,只需将整个事务包装到子事务中,然后可以根据需要在主事务内重新运行。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.