【发布时间】:2018-09-12 01:05:38
【问题描述】:
使用 PostgreSQL 9.6 和 PHP 7.2,我正在创建一个 PDO 连接,准备一个 INSERT 查询,绑定参数,然后执行准备好的查询。我将ATTR_ERRMODE 设置为ERRMODE_EXCEPTION,实际上可能会导致执行抛出异常,例如,准备好的查询有4 个参数,但我只绑定了3 个。
但是,如果我准备好的查询不包含具有 NOT NULL 约束的字段,则执行可能会挂起 20 秒,然后浏览器会显示“连接已重置”。 Postgres 日志说:
ERROR: null value in column "fullname" violates not-null constraint
DETAIL: Failing row contains (345, fredf, fredf@bedrock.net, yabadabadoo, null, Bedrock, none, user).
STATEMENT: INSERT INTO users (username, password, location, description, email, role) VALUES ($1, $2, $3, $4, $5, $6)
LOG: could not receive data from client: An existing connection was forcibly closed by the remote host.
这 4 个日志条目总共重复了 10 次。
我理解这种情况确实是一个编程问题——查询应该符合数据库设计的要求。但我真的很想哄 Postgres PDO 驱动程序告诉我错误是什么,而不是去挖掘日志。
示例代码
/*
Sample code to demonstrate failure of prepared query execute()
to throw an exception when the prepared query omits a field
with a NOT NULL constraint.
CREATE TABLE users (
id SERIAL PRIMARY KEY,
username varchar(50) NOT NULL,
email varchar(100) NOT NULL,
password varchar(255) NOT NULL,
fullname varchar(100) NOT NULL,
location varchar(100) NOT NULL,
description text NOT NULL,
role varchar(50) NOT NULL DEFAULT ''
);
*/
$host = "localhost";
$user = "postgres";
$pass = "password";
$dbname = "database";
/**
* Initialize the PDO connection.
*/
$dsn = 'pgsql:host=' . $host . ';dbname=' . $dbname;
$options = [
PDO::ATTR_PERSISTENT => true,
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
];
try {
$handler = new PDO($dsn, $user, $pass, $options);
} catch (PDOException $e) {
echo $e->getMessage();
die();
}
/**
* Demonstrate failure of execute() to return an error or throw an exception
* Error condition omits the fullname field from the INSERT query, which has a
* "not null" constraint.
*/
$demonstrateProblem = 1;
$badQuery = "INSERT INTO users (username, password, location, description, email, role) " .
"VALUES (:username, :password, :location, :description, :email, :role)";
$goodQuery = "INSERT INTO users (username, password, fullname, location, description, email, role) " .
"VALUES (:username, :password, :fullname, :location, :description, :email, :role)";
if ($demonstrateProblem == 1) {
$query = $badQuery;
} else {
$query = $goodQuery;
}
$stmt = $handler->prepare($query);
if (!$stmt) {
echo "Error in prepare, errorInfo():<br>";
print_r($handler->errorInfo());
}
/**
* Bind the variables
*/
$username = "fredf";
$password = "yabadabadoo";
$fullname = "Fred Flintstone";
$location = "Bedrock";
$description = "none";
$email = "fredf@bedrock.net";
$role = "user";
$stmt->bindParam(':username', $username);
$stmt->bindParam(':password', $password);
if ($demonstrateProblem == 0) {
$stmt->bindParam(':fullname', $fullname);
} else {
// nothing to do, :fullname is not in the prepared query!
}
$stmt->bindParam(':location', $location);
$stmt->bindParam(':description', $description);
$stmt->bindParam(':email', $email);
$stmt->bindParam(':role', $role);
/**
* Execute a prepared statement.
*/
echo "Executing prepared query...<br>";
try {
$res = $stmt->execute(); // <-- this statement hangs when the query prepare is bad.
if ($res) {
echo "execute returns true<br> ";
} else {
echo "execute returns false<br> ";
}
} catch (PDOException $e) {
echo "execute error " . $e->getMessage(); // <-- this never appears
}
PostgreSQL 日志(序列重复 10 次)
ERROR: null value in column "fullname" violates not-null constraint
DETAIL: Failing row contains (345, fredf, fredf@bedrock.net, yabadabadoo, null, Bedrock, none, user).
STATEMENT: INSERT INTO users (username, password, location, description, email, role) VALUES ($1, $2, $3, $4, $5, $6)
LOG: could not receive data from client: An existing connection was forcibly closed by the remote host.
【问题讨论】:
-
您是否使用
try ... catch将您的SQL 调用包装在PHP 中以捕获异常?当然,您可以缩写您的 PHP 代码块,而不需要 100 行。 -
是的,异常处理程序可以完美地处理其他错误,例如查询包含 4 个参数,但只绑定了 3 个。我会看看我是否可以缩短代码,但要到早上才能做到,谢谢。
-
你是怎么运行这个的?您是否使用框架来运行它?通过网络?尝试在命令行离线运行。
-
我从 Apache24 的本地 (Windows 10) 安装运行它。该代码基于我在 github 上找到的小型演示,而不是框架。您认为从 cmd 行运行的想法是一个很好的想法,实际上它确实会以这种方式抛出异常。所以也许这在我的 Apache 配置中有问题——如果您有任何想法,请使用 LMK?
-
在 Apache 上如何调用 PHP 脚本?导航到其网页?你说的挂是什么意思?如果您正在谈论一个空白的白页,这可能意味着您的错误尝试运行后的代码。检查 apache 错误日志以获取任何消息。尝试在
catch中回显消息后添加exit。
标签: php postgresql