2016-06-21 54 views
6

如果拋出數據庫異常,PDO的inTransaction()仍然在事務中返回false。這可能特定於使用PostgreSQL。例如PDO inTransaction()在數據庫異常後返回false

try { 
    $pdo->beginTransaction(); 
    $pdo->exec('SET TRANSACTION ISOLATION LEVEL SERIALIZABLE'); 
    // ... 
    // Cause any PDO exception 
    // ... 
    $pdo->commit(); 
} catch (\Exception $e) { 
    if ($pdo->inTransaction()) { 
     // Never gets here 
     $pdo->rollback(); 
    } 
    throw $e; 
} 

事務完全沒有結束,因爲如果我啓動另一個事件,我會得到一個異常,表明事務正在進行。我沒有測試過任何類型的異常,但肯定是發生在SQLSTATE[40001]: Serialization failure和主鍵違規。 這是預期的行爲還是PHP中的錯誤?

似乎知道回滾的唯一方法是保留一個單獨的變量,以知道我在交易中,使得inTransaction()無用。我注意到一些開源框架(如Doctrine)和應用程序(如Drupal)保留其自己的變量以處理事務狀態。 爲什麼我們不能依靠驅動程序或數據庫來告訴我們交易是否正在進行?

PHP 5.5.32和PostgreSQL 9.4。發現了一個兩年前的相關bug report,該版本在較早版本的PHP中被關閉。

+0

請參閱http://stackoverflow.com/questions/22743357/autorollback-in-postgres-using-pdo的答案......從它的外觀來看,「問題」就像PostgreSQL不是PHP和你看到的是正常的。 – Dave

回答

4

回答您的問題:

這是預期的行爲,或者是在PHP中的錯誤?

不是這不是預期的行爲,必須是PDO PgSQL擴展中的錯誤。

爲什麼我們不能依靠驅動程序或數據庫告訴我們一個 事務是否正在進行?

因爲驅動程序和數據庫是由人類創建的。在創建如此高度複雜的應用程序(如數據庫或驅動程序)時,人類可能會犯錯誤。對我來說,你的問題看起來不是邊緣案例,也可能導致任何db中的嚴重完整性問題。您可能還想考慮在php bug跟蹤器上打開代碼。

補丁代碼分析

不過,我看着它一點點。比較2年前(source)和當前代碼(source)的補丁代碼顯示,自補丁發生錯誤以來沒有任何更改。至少在那些直接受影響的功能中,它可能也是一個稍微不同的bug。所以我的猜測是,有其他的東西當然不會幫助你解決你的問題。

一個可能的工作圍繞當前proble米:

你可以檢查,如果你的連接有未完成的事務。爲此,您需要在遇到異常時創建第二個連接。首先確定您當前的連接ID。

SELECT pg_backend_pid();

在我的情況下,它返回的數字19339。在啓動會導致異常的查詢之前,應該保存該號碼。 現在在您的catch塊中,您需要查看錶格pg_catalog.pg_stat_activity

查找舊的連接,看看它的狀態是

activeidle in transactionidle in transaction (aborted)

有:

SELECT state FROM pg_catalog.pg_stat_activity WHERE pid=19339;

如果返回idle沒有當前事務爲舊的連接。如果它是上面三個之一,那麼交易仍然有效。來自postgresql的手冊說:

active: The backend is executing a query. 
idle: The backend is waiting for a new client command. 
idle in transaction: The backend is in a transaction, but is not currently executing a query. 
idle in transaction (aborted): This state is similar to idle in transaction, except one of the statements in the transaction caused an error. 
fastpath function call: The backend is executing a fast-path function. 
disabled: This state is reported if track_activities is disabled in this backend. 

最後一個狀態表明這一切的缺點。 它只有在track_activities配置標誌設置爲true時纔有效。