从实际角度来看,使用事务时有两种类型的错误消息
-"正常" 错误:在这种情况下,应用程序应停止当前进程并向用户显示错误消息。
-死锁错误。这表明 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("deadlock"); }
}
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("Can't connect to database server."));
}
}
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