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

时间:2013-12-14 14:11:31

标签: node.js postgresql concurrency transactions

通过事务我的意思是在begin isolation level serializable块中包含(例如)几个SQL语句。并发事务可以使此事务失败,即回滚。

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

2 个答案:

答案 0 :(得分:3)

您需要使用特定于客户端驱动程序的机制来检测事务中的错误。当您看到错误时,您必须回滚事务重新发布整个事务。你不能只重新做最近的部分 1

ROLLBACK是必需的;如果你不这样做,那么该连接上的任何进一步操作都会因“事务中止”错误而失败。

大多数客户端驱动程序抛出异常(使用支持它们的语言)来指示SQL错误,或者希望您在每次数据库操作后检查错误代码,方法是检查函数返回代码,或者调用特殊函数检查错误。 node-postgres是异步且非阻塞的,因此不太可能抛出异常;您应该寻找一个函数,让您查询会话中最后一个操作的SQLSTATE和客户端驱动程序错误状态。

node-postgres doesn't seem to have abundant documentation因此,您最好的选择是检查node-postgres的源代码,或者查找其他人如何执行此操作的示例。我希望你能找到检查会话错误状态的函数。您正在寻找的是为连接上的最后一次操作获取SQLSTATE的函数。

可能值得发布一个专门针对如何检测和处理node-postgres中的错误的问题。


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

答案 1 :(得分:0)

这个答案在3年后被添加,以说明自那以来的变化。尽管最初的答案仍然有效,但这个答案显示了今天使用当时无法使用的正确工具是多么容易。

使用pg-promise很容易,它支持任何嵌套级别的嵌套事务。请参阅Nested Transactions,其中说明顶级交易由您的标准using System; using System.Collections.Generic; namespace ConsoleApplication1 { class RnDHash { static void Main() { HashSet<int> rndIndexes = new HashSet<int>(); Random rng = new Random(); int maxNumber; Console.Write("Please input Max number: "); maxNumber = int.Parse(Console.ReadLine()); int iter = 0; while (rndIndexes.Count != maxNumber) { int index = rng.Next(maxNumber); rndIndexes.Add(index); iter++; } Console.WriteLine("Random numbers were found in {0} iterations: ", iter); foreach (int num in rndIndexes) { Console.WriteLine(num); } Console.ReadKey(); } } } - &gt; BEGIN / COMMIT表示,所有嵌套交易自动成为{{1} }。

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失败,我们仍然可以成功完成顶级交易。

如果您希望能够重新启动整个事务,只需将整个事务包装到子事务中,然后您可以根据需要在主事务内重新运行。