2016-07-25 103 views
1

我正在使用pg-promise來運行我的SQL查詢。查詢本身存儲在外部.sql文件中。Postgresql捕捉交易錯誤和回滾

當我執行一個事務時,如果發生錯誤(如預期的那樣),Postgres將中止事務。我遇到的問題是,在事務中止後嘗試運行的任何單獨查詢都不會運行,而是我會收到此消息: 「當前事務中止,命令被忽略,直到事務塊結束」。如果查詢是在psql控制檯中運行的,我可以通過在查詢失敗後發出ROLLBACK來解決這個問題。我不認爲這是一個選項,因爲我的應用程序使用的SQL位於外部文件中。我也不認爲保存點是一個選項,因爲如果失敗了,整個事務應該被拋出。

如果發生此錯誤,我將如何在SQL文件中回滾?

這裏的SQL以供參考:

BEGIN; 

DELETE 
FROM tournament_tossup_values 
WHERE tournament_id = $1 AND 
NOT EXISTS 
(
    SELECT id 
    FROM tournament_match 
    WHERE tournament_id = $1 
); 

UPDATE tournament 
SET bonus_point_value = $5, parts_per_bonus = $6 
WHERE id = $1 AND NOT EXISTS (
    SELECT id 
    FROM tournament_match 
    WHERE tournament_id = $1 
) 
RETURNING bonus_point_value, parts_per_bonus; <-- Any subsequent accesses to the database by the application fail if this transaction fails 

COMMIT; <-- I want to rollback everything if this fails 

預先感謝您!

+0

你是指圖書館[pg-promise](https://github.com/vitaly-t/pg-promise),但是你沒有使用它對事務的支持 - 方法'tx'?在這種情況下,我們不能確定發生了什麼,因爲你沒有顯示你正在做什麼的完整代碼。也許最好是使用'tx'方法,並在其中執行查詢,如所有示例中所示。查看[交易](https://github.com/vitaly-t/pg-promise#transactions)。這會讓你的代碼更具可預測性,因爲你不會在SQL中提供正確的'ROLLBACK'邏輯。 –

回答

1

在外部SQL文件中實現事務時,您需要爲COMMITROLLBACK提供所有適當的處理。當你不這樣做時,交易狀態可能在你的服務器端代碼中變得不可預測,並導致你得到的錯誤類型。

這可能有點棘手,說起來容易做起來難。這就是爲什麼最好的解決辦法是不要這樣做。

您已經使用的模塊pg-promise通過方法tx爲交易提供了可靠的處理,這是您應該使用的。

爲此,拆你的SQL文件到兩個文件 - 一個與你的DELETE操作和一個與你UPDATE操作,然後執行它們在事務中的兩個查詢:

db.tx(t => { 
    return t.batch([ 
     t.none('DELETE...'), 
     t.any('UPDATE...') 
    ]); 
}) 
    .then(data => { 
     // success; 
    }) 
    .catch(error => { 
     // error; 
    }); 
+0

啊,那個解決辦法就是我所接近的。只是想確保沒有解決方案可以讓我將所有內容都保存在一個SQL文件中。我會繼續按照上面概述的方式實施它。謝謝! :) – mbhuiyan

+0

@mbhuiyan可以有一個單一文件的解決方案,但是實現和使用會比較麻煩,當一個'pg-promise'事務更容易使用時,這並不值得。 –