PDO "Integrity constraint violation - Duplicate entry",但 table 中没有重复项
PDO "Integrity constraint violation - Duplicate entry", but no duplicates in table
我得到 "Duplicate entry" 一个插入查询,它与旧的 mysqli 函数一起工作得很好。一旦我转换为 PDO,相同的插入语句就会中断。
这是示例 SQL 数据
CREATE TABLE IF NOT EXISTS `lookup_codes` (
`id` int(3) NOT NULL,
`code` varchar(10) NOT NULL,
PRIMARY KEY (`id`,`code`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
INSERT INTO `lookup_codes` (`id`, `code`) VALUES
(1, 'AR'),
(1, 'CN'),
(1, 'OA'),
(4, 'AR'),
(4, 'OA');
这里是示例 php/pdo 代码。 (这不是代码评论请求 - 只是试图将问题归结为一个简单的示例,请勿在生产中使用此代码,yada yada)。
// posted data from user
$id = 2;
$arr_codes = array('AR','CN');
// make sure existing rows do not exist
try
{
$q = "SELECT COUNT(*) FROM lookup_codes WHERE id=:id";
if ($dbg) { echo "<p>SELECT COUNT(*) FROM lookup_codes WHERE id=$id<br>";}
$stmt = $dbx_pdo->prepare($q);
$stmt->bindParam(':id', $id, PDO::PARAM_INT);
$stmt->execute();
list($count_rows) = $stmt->fetch(PDO::FETCH_NUM); $stmt->closeCursor();
if ($count_rows>0)
{
try
{
$q = "DELETE FROM lookup_codes WHERE id=:id";
if ($dbg) { echo "<p>DELETE FROM lookup_codes WHERE id=$id<br>";}
$stmt = $dbx_pdo->prepare($q);
$stmt->bindParam(':id', $id, PDO::PARAM_INT);
$stmt->execute();
$stmt->closeCursor();
} catch(PDOException $err) {
echo $err->getMessage());
exit;
}
}
} catch(PDOException $err) {
echo $err->getMessage());
exit;
}
// set up prepared statement based on posted data
foreach ($arr_codes as $code)
{
$arr_ip[] = array(
'id' => $id,
'code' => $code,
);
}
$txt_prepared = join(',', array_fill(0, count($arr_ip), '( ?, ?)'));
// try inserting
try
{
$q = "INSERT INTO lookup_codes (id, code) VALUES $txt_prepared";
$stmt = $dbx_pdo->prepare($q);
$cb = 1;
foreach ($arr_ip as $rip)
{
$id = $rip['id'];
$code = $rip['code'];
$stmt->bindParam($cb++, $id, PDO::PARAM_INT);
$stmt->bindParam($cb++, $code, PDO::PARAM_STR);
if ($dbg) { echo "<b>Binding</b> ($id, $code)<br>";}
}
$stmt->execute();
$stmt->closeCursor();
} catch(PDOException $err) {
echo $err->getMessage());
exit;
}
这就是我的测试脚本中的全部内容。没有 header 或元重定向.. 这里只有一个 运行 代码。
上面的例子导致:
Error: SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate
entry '2-CN' for key 'PRIMARY'
请注意,它会在 second 提交的代码中返回重复项。
相同的 INSERT
在使用 mysqli_query()
时工作得很好。没有错误写入错误日志。
这是怎么回事?
问题在于您绑定插入查询的方式。您需要将 $stmt->bindParam
更改为 $stmt->bindValue
。 bindParam 通过引用获取变量,因此在循环的每次迭代中,当您更改 $id 和 $code 的值时,您正在更改绑定的值。 bindValue 将从变量中获取值的副本并将其绑定。
我得到 "Duplicate entry" 一个插入查询,它与旧的 mysqli 函数一起工作得很好。一旦我转换为 PDO,相同的插入语句就会中断。
这是示例 SQL 数据
CREATE TABLE IF NOT EXISTS `lookup_codes` (
`id` int(3) NOT NULL,
`code` varchar(10) NOT NULL,
PRIMARY KEY (`id`,`code`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
INSERT INTO `lookup_codes` (`id`, `code`) VALUES
(1, 'AR'),
(1, 'CN'),
(1, 'OA'),
(4, 'AR'),
(4, 'OA');
这里是示例 php/pdo 代码。 (这不是代码评论请求 - 只是试图将问题归结为一个简单的示例,请勿在生产中使用此代码,yada yada)。
// posted data from user
$id = 2;
$arr_codes = array('AR','CN');
// make sure existing rows do not exist
try
{
$q = "SELECT COUNT(*) FROM lookup_codes WHERE id=:id";
if ($dbg) { echo "<p>SELECT COUNT(*) FROM lookup_codes WHERE id=$id<br>";}
$stmt = $dbx_pdo->prepare($q);
$stmt->bindParam(':id', $id, PDO::PARAM_INT);
$stmt->execute();
list($count_rows) = $stmt->fetch(PDO::FETCH_NUM); $stmt->closeCursor();
if ($count_rows>0)
{
try
{
$q = "DELETE FROM lookup_codes WHERE id=:id";
if ($dbg) { echo "<p>DELETE FROM lookup_codes WHERE id=$id<br>";}
$stmt = $dbx_pdo->prepare($q);
$stmt->bindParam(':id', $id, PDO::PARAM_INT);
$stmt->execute();
$stmt->closeCursor();
} catch(PDOException $err) {
echo $err->getMessage());
exit;
}
}
} catch(PDOException $err) {
echo $err->getMessage());
exit;
}
// set up prepared statement based on posted data
foreach ($arr_codes as $code)
{
$arr_ip[] = array(
'id' => $id,
'code' => $code,
);
}
$txt_prepared = join(',', array_fill(0, count($arr_ip), '( ?, ?)'));
// try inserting
try
{
$q = "INSERT INTO lookup_codes (id, code) VALUES $txt_prepared";
$stmt = $dbx_pdo->prepare($q);
$cb = 1;
foreach ($arr_ip as $rip)
{
$id = $rip['id'];
$code = $rip['code'];
$stmt->bindParam($cb++, $id, PDO::PARAM_INT);
$stmt->bindParam($cb++, $code, PDO::PARAM_STR);
if ($dbg) { echo "<b>Binding</b> ($id, $code)<br>";}
}
$stmt->execute();
$stmt->closeCursor();
} catch(PDOException $err) {
echo $err->getMessage());
exit;
}
这就是我的测试脚本中的全部内容。没有 header 或元重定向.. 这里只有一个 运行 代码。
上面的例子导致:
Error: SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry '2-CN' for key 'PRIMARY'
请注意,它会在 second 提交的代码中返回重复项。
相同的 INSERT
在使用 mysqli_query()
时工作得很好。没有错误写入错误日志。
这是怎么回事?
问题在于您绑定插入查询的方式。您需要将 $stmt->bindParam
更改为 $stmt->bindValue
。 bindParam 通过引用获取变量,因此在循环的每次迭代中,当您更改 $id 和 $code 的值时,您正在更改绑定的值。 bindValue 将从变量中获取值的副本并将其绑定。