從實務的角度來看,使用交易時有兩種類型的錯誤訊息
-「一般」錯誤:在這種情況下,應用程式應停止目前的處理程序,並向使用者顯示錯誤訊息。
-死結錯誤。這表示 PostgreSQL 的死結偵測程序發現了一個循環依賴關係,並透過回滾其中一個程序中的交易來打破它,該程序會收到此錯誤訊息。在這種情況下,應用程式不應停止,而應重複執行交易。
我沒有找到任何明確的方法來判斷我們正在處理哪種情況。此介面不支援錯誤碼,因此我們必須在訊息文字中搜尋模式。
以下是一個 PostgreSQL 資料庫連線類別的範例。它會在「一般」錯誤時拋出 PostgresException,在發生死結且需要重複交易時拋出 DependencyException。
postgres.php
<?php
class PostgresException extends Exception {
function __construct($msg) { parent::__construct($msg); }
}
class DependencyException extends PostgresException {
function __construct() { parent::__construct("死結"); }
}
class pg {
public static $connection;
private static function connect() {
self::$connection = @pg_connect("dbname=foodb user=foouser password=foopasswd");
if (self::$connection === FALSE) {
throw(new PostgresException("無法連線到資料庫伺服器。"));
}
}
public static function query($sql) {
if (!isset(self::$connection)) {
self::connect();
}
$result = @pg_query(self::$connection, $sql);
if ($result === FALSE) {
$error = pg_last_error(self::$connection);
if (stripos($error, "deadlock detected") !== false) throw(new DependencyException());
throw(new PostgresException($error.": ".$sql));
}
$out = array();
while ( ($d = pg_fetch_assoc($result)) !== FALSE) {
$out[] = $d;
}
return $out;
}
}
?>
它應該以這種方式使用
test.php
<?php
include("postgres.php");
do {
$repeat = false;
try {
pg::query("begin");
...
$result = pg::query("SELECT * FROM public.kitten");
...
pg::query("commit");
}
catch (DependencyException $e) {
pg::query("rollback");
$repeat = true;
}
} while ($repeat);
?>
一般的錯誤應該在前端被捕獲。
Tamas