更新重复密钥时发生错误

时间:2018-08-02 08:54:16

标签: php mysql

你能告诉我我做错了吗?

我有一个功能,可以在数据库中添加users_id,attribute_id和用户输入的答案。 直到它起作用。但是,当我添加ON DUPLICATE KEY UPDATE部分来更新用户答案而不创建新的答案时,会抛出错误:

  

致命错误:未被捕获的错误:在第39行的...... \ Attributes.php中,对布尔值的成员函数execute()进行调用

在那一行上,我有$ add_user-> execute();

下面添加了插入数据库的函数。如果我删除“重复更新”部分,它将插入数据库中,并且一切正常,但是我需要,如果用户已经回答过,它会更新现有文件,而不会在数据库中插入新数据:

    public function updateAttributes($attribute_id, $attribute_text) {
    $dbobj = new Connection();
    $connection = $dbobj->getConnection();

    $user_id = $_SESSION['id'];
    $_attribute_id = mysqli_real_escape_string($connection, $attribute_id);
    $attribute = mysqli_real_escape_string($connection, $attribute_text);

    $add_user = $connection->prepare("INSERT into user_answers(user_id, attribute_id, answer) VALUES ('$user_id', '$_attribute_id', '$attribute') ON DUPLICATE KEY UPDATE answer = VALUES(answer) WHERE user_id = VALUES(user_id) AND attribute_id =  VALUES(attribute_id)");
    //$add_user->bind_param('iis', $user_id, $_attribute_id, $attribute);
    // ON DUPLICATE KEY UPDATE user_answer = VALUES(answer) WHERE user_id = VALUES(user_id) AND attribute_id =  VALUES(attribute_id)

    $add_user->execute();
    $add_user->close();
    $connection->close();
}

如果需要,这里是sql代码。包含两个外键和答案,用于存储用户输入的答案:

CREATE TABLE IF NOT EXISTS `user_answers` (
  `user_id` int(11) DEFAULT NULL,
  `attribute_id` int(11) DEFAULT NULL,
  `answer` varchar(50) DEFAULT NULL,
  KEY `user_id` (`user_id`),
  KEY `attribute_id` (`attribute_id`),
  CONSTRAINT `attribute_id` FOREIGN KEY (`attribute_id`) REFERENCES `attributes` (`id`),
  CONSTRAINT `user_id` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

更新:添加了连接类别:

class Connection {
    public function getConnection(){
        $conn = mysqli_connect("localhost","root","","dbname") or die("Couldn't connect");
        $conn->query("SET NAMES utf8");
        return $conn;
    }
}

编辑

更新代码后,我遇到了这个问题:

下面添加了插入数据库的函数。如果我删除“重复更新”部分,它将插入数据库中,并且一切正常,但是我需要,如果用户已经回答过,它会更新现有文件,而不会在数据库中插入新数据:

公共函数updateAttributes($ attribute_id,$ attribute_text){     $ dbobj = new Connection();     $ connection = $ dbobj-> getConnection();

$user_id = $_SESSION['id'];
$_attribute_id = mysqli_real_escape_string($connection, $attribute_id);
$attribute = mysqli_real_escape_string($connection, $attribute_text);

$add_user = $connection->prepare("INSERT into user_answers(user_id, attribute_id, answer) VALUES (?, ?, ?) ON DUPLICATE KEY UPDATE answer = VALUES(answer)");
$add_user->bind_param('iis', $user_id, $_attribute_id, $attribute);

$add_user->execute();
$add_user->close();
$connection->close();

}

2 个答案:

答案 0 :(得分:1)

由于ON DUPLICATE KEY UPDATE子句不应包含WHERE子句,导致错误是由于准备失败而引起的。要插入的数据已经与现有键匹配,因此WHERE子句是多余的,因此已经定义了要更新的行。尝试将代码更改为:

$add_user = $connection->prepare("INSERT into user_answers(user_id, attribute_id, answer) VALUES ('$user_id', '$_attribute_id', '$attribute') ON DUPLICATE KEY UPDATE answer = VALUES(answer)");

答案 1 :(得分:1)

您正在将变量注入字符串中,从而无法达到准备SQL语句的目的...您正在让应用程序对SQL注入攻击敞开大门。

$add_user = $connection->prepare("INSERT into user_answers(user_id, attribute_id, answer)
                                  VALUES ('$user_id', '$_attribute_id', '$attribute') 
                                        --^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-- this is is plain wrong
                                  ON DUPLICATE KEY UPDATE answer = VALUES(answer)  
                                  WHERE user_id = VALUES(user_id) AND attribute_id =  VALUES(attribute_id)");

准备工作可能会失败,从而导致其返回false

http://php.net/manual/en/pdo.prepare.php

  

如果数据库服务器无法成功准备语句,则PDO :: prepare()返回FALSE 或发出PDOException(取决于错误处理)。

请按需准备。

$add_user = $connection->prepare("INSERT into user_answers(user_id, attribute_id, answer) VALUES (:user_id, :attribute_id, :attribute) ON DUPLICATE KEY UPDATE answer = VALUES(answer) WHERE user_id = VALUES(user_id) AND attribute_id =  VALUES(attribute_id)");
// Inject the variables you want in the prepared statement.

$result = $add_user->execute([
   ':user_id' => $user_id,
   ':attribute_id' => $_attribute_id,
   ':attribute' => $attribute,
]);

还有Nick在他的answer沟中指出了位置。

现在,对于重复密钥问题。数据库如何识别主键是哪个键?您现在已经定义了两个键。这就是为什么您必须定义主键的原因。在执行此语句之前,您可能必须截断表或删除重复项。

ALTER TABLE user_answers ADD PRIMARY KEY (user_id);