从实际角度来看,使用事务时存在两种类型的错误消息
-“普通”错误:在这种情况下,应用程序应停止当前进程并向用户显示错误消息。
-死锁错误。这表明 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("无法连接到数据库服务器。"));
}
}
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);
?>
正常的错误应该在前端捕获。
塔马什