2013-12-14 55 views
1

通過事務我的意思是幾個SQL語句在begin isolation level serializable塊中包裝(例如)。併發事務可能導致此事務失敗,即回滾。在PostgreSQL中重新啓動一個失敗的事務

如何在PostgreSQL中重新啓動失敗的事務?

+1

您必須留意此類事件,並準備好再次從客戶端開始相同的事務,以防在失敗後該操作仍然有效。 –

+0

但是,當交易失敗時,所有客戶都會收到通知嗎?我正在使用node-postgres(node.js),但我不確定事務失敗是否會引發異常。 – ehmicky

+1

[pg-promise](https://github.com/vitaly-t/pg-promise)支持嵌套事務,並且這些成爲嵌套級別上的保存點,您可以使用它來恢復事務。 –

回答

3

您需要使用客戶端驅動程序特定的機制來檢測事務中的錯誤。當你看到一個錯誤,你必須回滾交易重新發出整個交易。你不能只重新做最近的部分。

ROLLBACK是必需的;如果您不這樣做,則該連接的任何進一步操作都會失敗,並顯示「事務中止」錯誤。

大多數客戶端驅動程序要麼在支持它們的語言中引發異常來指示SQL錯誤,要麼在每次數據庫操作之後檢查錯誤代碼(通過檢查函數返回代碼或調用特殊函數檢查錯誤。 node-postgres是異步和非阻塞的,所以不會拋出異常;您應該查找一個函數,通過該函數可以查詢會話以瞭解上一次操作產生的SQLSTATE和客戶端驅動程序錯誤狀態。

node-postgresdoesn't seem to have abundant documentation因此,您最好的選擇可能是檢查node-postgres的源代碼,或查找其他人如何執行此操作的示例。我希望你會找到函數來檢查會話的錯誤狀態。您正在尋找的功能是獲取SQLSTATE用於連接上的最後一項操作。

它可能是值得發佈的問題,專門關注如何檢測和處理node-postgres中的錯誤。


其實,SAVEPOINTROLLBACK TO SAVEPOINT讓你做到這些,但他們不會與序列化錯誤的幫助。

+0

這實際上是我想要的那種答案。非常感謝! – ehmicky

0

此答案已在3年後添加,以解釋此後的變化。即使原始答案仍然有效,這個答案顯示了今天使用當時沒有的正確工具是多麼容易。


這是很容易做到與pg-promise,它支持任意嵌套層次的嵌套事務。請參閱Nested Transactions,其中說明儘管頂級交易由標準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失敗,我們仍然可以成功完成我們的頂級交易。

如果您希望能夠重新啓動整個事務,只需將整個事件包裝到一個子事務中,然後您可以根據需要多次在主事務中重新運行該子事務。