2016-06-21 10 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。 2年前に関連したbug reportがPHPの古いバージョンでは閉じられています。

+0

答えはhttp://stackoverflow.com/questions/22743357/autorollback-in-postgres-using-pdo .....のようになります。見た目からは「問題」はそのままの状態でPostgreSQLはPHPではありません。あなたが見ているものは正常です。 – Dave

答えて

4

あなたの質問に答えるために:

は、この予想される動作ですかそれはPHPのバグですか?

これは予期した動作ではなく、PDO PgSQL拡張のバグでなければなりません。我々は トランザクションが進行中である場合は、私たちに伝えるために、ドライバまたはデータベースに頼ることができないのはなぜ

ドライバとデータベースは人間によって作成されているためです。また、データベースやドライバのような非常に複雑なアプリケーションを作成するときに、人間は間違いを犯す可能性があります。私にとっては、問題はそれが最悪のケースではないように見え、どのdbでも深刻な完全性の問題を引き起こす可能性があります。また、PHPバグトラッカーでティッカーを開くことを検討したいかもしれません。

は、しかし、私はもう少しそれに見えたにパッチコード分析。 2年前のパッチ(source)と現在のコード(source)のコードを比較すると、そのエラーにパッチを当てて何も変わっていないことがわかります。これらの直接的な影響を受けた機能には少なくともありません。だから、私の推測では、あなたの問題を解決するのに役立つものは何もないということです。

現在probleメートルの周りの可能性仕事:あなたの接続が優れたトランザクションを持っている場合は、チェックすることができ

。このためには、例外発生時に2番目の接続を作成する必要があります。まず、現在の接続IDを特定します。私の場合は

SELECT pg_backend_pid();

それは数19339を返しました。例外を引き起こすクエリを起動する前に、この番号を保存する必要があります。 キャッチブロックには、テーブルpg_catalog.pg_stat_activityを参照する必要があります。

で古い接続を検索して、それはステータスが

activeあるのですかどうかを確認、idle in transactionまたはidle in transaction (aborted)

:それはidleを返した場合、そのための現在のトランザクションが存在しない

SELECT state FROM pg_catalog.pg_stat_activity WHERE pid=19339;

古い接続。それが上位3つの場合は、まだアクティブなトランザクションがあります。 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に設定されている場合にのみ機能します。

関連する問題