【问题标题】:UPDATE table record instead of adding a new record MySQLUPDATE 表记录而不是添加新记录 MySQL
【发布时间】:2016-05-14 15:05:58
【问题描述】:

好的..事情就是这样。我想列出已登录的用户并在注销时更改其状态。这很完美。我为此创建了一个名为 tblaudit_users 的表。我从 tbl_users 表中选择的现有用户。

我想要的是,如果用户已经存在于 tblaudit_users 表中,它将使用 NOW() 更新 LastTimeSeen 时间。但它不会更新该记录,而是创建一个新记录。这样桌子就会越来越大,我想避免这种情况。我用于此的代码如下所示:

++++++++++++++++++++++

$ipaddress = $_SERVER['REMOTE_ADDR'];

if(isset($_SESSION['id'])){

    $userId = $_SESSION['id'];
    $username = $_SESSION['username'];
    $achternaam = $_SESSION['achternaam'];
    $district = $_SESSION['district'];
    $gemeente = $_SESSION['gemeente'];

    $query = $db->prepare("SELECT * FROM tblaudit_users WHERE username = '{$username}' AND active = '1' LIMIT 1");
    $query->execute();

    foreach($query->fetchAll(PDO::FETCH_OBJ) as $value){
        $duplicate = $value->username;  
    }

    if($duplicate != 1){

        $insert = $db->prepare("
                    INSERT INTO tblaudit_users (user_id, username, achternaam, district, gemeente, ipaddress, LastTimeSeen, status)
                    VALUES ('{$userId}', '{$username}', '{$achternaam}', '{$district}', '{$gemeente}', '{$ipaddress}', NOW(), '1')
                    ");
        $insert->execute();

    } elseif($duplicate = 1){

        $update = $db->prepare("UPDATE tblaudit_users SET LastTimeSeen = NOW(),status = '1' WHERE username = '{$username}'");
        $update->execute();

    } else {
        header('Location: index.php');
        die();
    }
}

我迷路了,搜索了很多网站/页面来解决这个问题,所以希望这里有人可以帮助我?提前致谢!!

更新:

我尝试了以下没有结果。

+++++

$insert = $db->prepare("
                    INSERT INTO tblaudit_users (user_id, username, achternaam, district, gemeente, ipaddress, LastTimeSeen, status)
                    VALUES ('{$userId}', '{$username}', '{$achternaam}', '{$district}', '{$gemeente}', '{$ipaddress}', NOW(), '1')
                    ON DUPLICATE KEY UPDATE set LastTimeSeen = NOW(), status = '1'
                    ");
        $insert->execute();

好的。我稍微修改了查询和代码:

$query = $db->prepare("SELECT * FROM tblaudit_users WHERE username = '{$username}' LIMIT 1");
$query->execute();

if($query){

    $insert = $db->prepare("
                INSERT INTO tblaudit_users (user_id, username, achternaam, district, gemeente, ipaddress, LastTimeSeen, status)
                VALUES ('{$userId}', '{$username}', '{$achternaam}', '{$district}', '{$gemeente}', '{$ipaddress}', NOW(), '1')
                ON DUPLICATE KEY UPDATE set LastTimeSeen = NOW(), status = '1'
                ");
    $insert->execute();

} else {
    header('Location: index.php');
    die();
}

}

我还添加了一个名为 pid(主 id)的唯一键。还是不行。

【问题讨论】:

  • 你试过MySQL语句语法INSERT ... ON DUPLICATE KEY UPDATE吗?如果没有,请尝试一下。如果是这样,请edit您的问题以展示您的尝试
  • @David:我已经尝试过了,但它不起作用。还从 $query 中删除了一些 WHERE 子句。 WHERE active='1' 不是表中的列。
  • tblaudit_users 有主键/唯一键吗?
  • 好像找不到$username的记录。我的猜测是我的“if”语句是错误的,但不知道为什么
  • 并且userid被设置为key?

标签: php mysql


【解决方案1】:

基于http://dev.mysql.com/doc/refman/5.7/en/insert-on-duplicate.html,不要在更新语法中使用'set'

页面示例:

INSERT INTO table (a,b,c) VALUES (4,5,6) ON DUPLICATE KEY UPDATE c=9;

【讨论】:

    【解决方案2】:

    几个问题:

    • 您在$query 上进行测试,但那是您的语句对象,即使您没有从select 语句返回的记录也将有效;
    • 在确保前一个已关闭或至少已获取其所有记录之前,访问第二个准备好的语句可能会出现问题;
    • insert 语句中存在语法错误(set 不应存在);
    • 要使insert ... on duplicate key update 起作用,您提供的值必须包含唯一键;
    • SQL 注入漏洞;
    • selectinsert 的不必要拆分:这可以在一个语句中完成

    您可以使用num_rows() 编写测试。要获得正确的计数,请致电store_result()。在发布下一个声明之前关闭一个声明也是一个好习惯:

    $query = $db->prepare("SELECT * FROM tblaudit_users 
                           WHERE username = '{$username}' LIMIT 1");
    $query->execute();
    $query->store_result();
    if($query->num_rows()){
         $query->close();
         // etc...
    

    但是,当您执行insert ... on duplicate key update 时,整个查询是不必要的:无需先检查select 该用户是否确实存在。这一切都由insert ... on duplicate key update 语句完成。

    INSERT 中的错误

    ON DUPLICATE KEY UPDATE 的语法后面不应有 SET 这个词。

    防止 SQL 注入

    尽管您使用准备好的语句(好!),但您仍然将字符串注入您的 SQL 语句(不好!)。准备好的语句的优点之一是您可以在查询中使用参数,而无需实际将字符串注入 SQL 字符串,使用 bind_param():

    $insert = $db->prepare("
        INSERT INTO tblaudit_users (user_id, username, achternaam, district, 
                                    gemeente, ipaddress, LastTimeSeen, status)
        VALUES (?, ?, ?, ?, ?, ?, NOW(), '1')
        ON DUPLICATE KEY UPDATE LastTimeSeen = NOW(), status = '1'
        ");
    $insert->bind_param("ssssss", $userId, $username, $achternaam, 
                                  $district, $gemeente, $ipaddress);
    $insert->execute();
    

    这样可以避免SQL injection

    确保user_idtblaudit_users 中具有唯一约束。将另一个(auto_increment)字段作为主键没有帮助。它必须是您为其插入值的字段之一。

    以上代码不再使用$query。你不需要它。

    【讨论】:

      【解决方案3】:

      我发现了问题

      if(isset($_SESSION['id'])){
      
          $userId = $_SESSION['id'];
          $username = $_SESSION['username'];
          $achternaam = $_SESSION['achternaam'];
          $district = $_SESSION['district'];
          $gemeente = $_SESSION['gemeente'];
      
          $query = $db->prepare("SELECT * FROM tblaudit_users WHERE user_id = '{$userId}' LIMIT 1");
          $query->execute();
      
          if($query->rowcount()<1){
      
            $insert = $db->prepare("
                        INSERT INTO tblaudit_users (user_id, username, achternaam, district, gemeente, ipaddress, LastTimeSeen, status)
                        VALUES ('{$userId}', '{$username}', '{$achternaam}', '{$district}', '{$gemeente}', '{$ipaddress}', NOW(), '1')
                        ");
            $insert->execute();
      
          } elseif($query->rowcount()>0) {
      
              $update = $db->prepare("UPDATE tblaudit_users SET LastTimeSeen = NOW(),status = '1' WHERE user_id = '{$userId}'");
              $update->execute(); 
      
          } else {
              header('Location: index.php');
              die();
          }
      }
      

      我没有在查询中使用 $username,而是选择了 $userId,它可以工作。

      【讨论】:

      • 您仍然容易受到 SQL 注入攻击,如果两个用户同时执行此脚本(并发),您的代码总有一天会失败。
      • @trincot:你能解释一下代码在哪里容易受到 SQL 注入的影响,以及为什么如果两个用户执行这个脚本会失败?谢谢
      • gemeente 等会话变量中插入INSERT 语句。由于它们在某些时候是由用户定义的,因此它们可能包含恶意代码,这会改变 SQL 语句的含义。阅读有关 SQL 注入的信息。如果两个用户几乎同时执行脚本,并且在他们的会话中都具有相同的用户 ID(例如,如果我使用两个浏览器窗口),那么两个用户都无法从第一个 SELECT 中获取任何记录,然后将两者都插入具有相同 user_id 值的记录,这不是您想要的。
      猜你喜欢
      • 2022-01-06
      • 2014-09-21
      • 1970-01-01
      • 2020-07-19
      • 2014-12-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-09-03
      相关资源
      最近更新 更多