【发布时间】:2018-07-04 04:39:55
【问题描述】:
我正在使用一个一直在处理我的代码的函数,现在我正在慢慢地从 MySQLi 迁移到 PDO - 这个函数应该“简单地”获取一条 SQL 语句和一组变量并设置准备好的语句,然后执行它并返回一个带有“成功/失败”代码的数组,然后是 lastInsertId。
到目前为止,该功能一直运行良好,考虑到我遇到的错误(而且我是 PDO 的新手),我想知道问题出在哪里。
首先,函数本身是相当良性的(常量在别处定义)
function dbConnect(){
try {
if(!defined('PDO::ATTR_DRIVER_NAME')){
debugPrint('Error: PDO unavailable');
return false;
}
$dsn = 'mysql:host=' . DB_SERVER . ';dbname=' . DB_NAME . ';charset=UTF8';
$opt = [
PDO::ATTR_EMULATE_PREPARES => false,
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC
];
$db = new PDO($dsn, DB_USER, DB_PASS, $opt);
return $db;
} catch (PDOException $e) {
debugPrint($e->getMessage());
return false;
}
}
function dbInsert($sql, $param){
$ret = [];
if(!$pdo = dbConnect()){
$ret[] = 1;
return $ret;
}
if(!$stmt = $pdo->prepare($sql){
echo $pdo->errorInfo();
$ret[] = 1;
return $ret;
}
if(!$stmt->execute($param)){
echo $pdo->errorInfo();
$ret[] = 1;
return $ret;
} else {
$ret[] = 0;
$ret[1] = $pdo->lastInsertId();
return $ret;
}
我正在编写代码,它只是检查电子邮件地址是否出现在表格中,如果没有,则插入它。我在我的应用程序中进行了很多检查,大约 50% 的时间提供的电子邮件将是现有条目。
$sql = 'insert into customer (email) select :email from DUAL where not exists (select 1 from customer where email = :email)';
$bind = [':email' => 'user@bogus.org'];
这是迄今为止我见过的最简洁的方法,它是对数据库的一次调用并使用准备好的语句。但是,我收到 PDO 错误“无效参数号”和堆栈跟踪错误。我已经打开了 MySQL 日志记录,看起来准备工作正常...
Prepare insert into customer (email) select ? from DUAL where not exists (select 1 from customer where email = ?)
...所以我只能认为它是绑定,考虑到参数错误的数量,这是有道理的,但异常似乎来自执行:
PHP Fatal error: Uncaught PDOException: SQLSTATE[HY093]: Invalid parameter number in {filename}:78
Stack trace:
#0 {filename}:78: PDOStatement->execute(Array)
#1 {callingFile(33)}: dbInsert('insert into cus...', Array)
#2 {main}
thrown in {filename} on line 78
由于我是 PDO 领域的新手并且热衷于学习,我想找出我应该在哪里解决这个问题。
我很喜欢 PDO 的功能,我希望这不是一个需要解决的太大问题,但目前我不知道为什么会抛出这个错误。我确实想知道是不是因为我使用的是“1”
注意:1 我知道我可以使电子邮件在表中唯一,但这意味着 $pdo->execute 返回非零,使我的函数返回非零(错误),这(至少在我看来)并不完全正确。
注意:2我也知道我可以先检查表格以查看电子邮件是否存在,如果不存在则插入它:但是,我不确定这是最好的做事的方式(并且由于我当前正在更新的代码这样做,我认为使其成为 PDO 以及可能对 SQL 调用本身更聪明)。
注意:3我还将 SQL 语句更改为以下内容:
$sql = 'insert ignore into customer (email) values (:email)';
$bind = [':email' => 'user@bogus.org'];
这是“OK”,但是如果存在现有电子邮件,则收件人表中的 auto_incremented 主键会跳过(再次尝试保持一切清洁、简单和合乎逻辑),我真的不想破解这个通过附加一个(慢)语句来更改表以将 auto_increment 设置为 1
【问题讨论】:
标签: mysql pdo prepared-statement