【问题标题】:Prevent duplicate insertion in database防止在数据库中重复插入
【发布时间】:2015-10-06 23:50:48
【问题描述】:

我正在向我的数据库中插入一些数据,这些数据位于两个表中。插入工作正常,但是当我再次尝试插入时,如果单元格有值,新值将插入到它旁边。如果单元格中已经有一个值,我尝试了一个 if/else 条件来防止新的插入,但未能使其工作。也许这不是解决方案,或者我做错了。请问有什么帮助吗?

if(isset($_POST['submit'])) {   
    $degree = $_POST['Degree'];
    $major = $_POST['Major'];
    $univ = $_POST['Univ'];
    $brevet = $_POST['Brevet'];
    $baccbt = $_POST['Baccbt'];
    $selectaf = $_POST['SelectAF'];

    $sql1="SELECT certificatesgrading.brevet,
                  certificatesgrading.baccbt,
                  university.degree,
                  university.major,
                  university.univ
           FROM   university,
                  certificatesgrading
           WHERE  afnumber = '$selectaf'";

    if ($result=mysqli_query($con,$sql1)) {
        // Return the number of rows in result set
        $rowcount=mysqli_num_rows($result);
    }

    $sql="INSERT INTO university
            (afnumber,
             university.degree,
             university.major,
             university.univ)
          VALUES   ('$selectaf',
                    '$degree',
                    '$major',
                    '$univ')";

            $sql1="INSERT INTO certificatesgrading
            (afnumber,
             certificatesgrading.brevet,
             certificatesgrading.baccbt)
             VALUES     ('$selectaf',
                         '$brevet',
                         '$baccbt') ";
            $result = mysql_query($sql);
            $result = mysql_query($sql1);


}
echo $menu;

【问题讨论】:

  • 这样做有用吗?如果是这样,为什么不直接使用它!我想不出一个“更好”的方法来做到这一点。
  • 第一个查询中universitycertificatesgradingwherejoin ... on之间应该有一个join condition就可以了。
  • @RyanVincent 抱歉,我没听懂你.. 在哪里申请加入?
  • @RyanVincent 还是一样
  • 请使用新代码更新您的问题。您仍然需要使用使用$rowcount 结果来决定是否插入新行的测试来包装插入。正如答案中已经提到的那样,这不会防止重复 - 请参阅@GordonM cmets。您可以使用transaction 来帮助解决该问题。

标签: php mysql phpmyadmin


【解决方案1】:

如果您想涵盖所有可能的情况,尤其是如果您想处理表之间的关系,这种行为是“难以”自行开发的。

我认为您应该考虑使用诸如doctrine 之类的 ORM。这样,您将能够在 ORM 为您处理和检查的数据模型上修复 constraints。还可以考虑将它与 Symfony2 等 PHP 框架一起使用。您不必实现完整的堆栈,根据您的需要使用一些组件就足够了。

以下是documentation 给出的示例以及注释的工作原理:

<?php
/**
 * @Entity
 * @Table(name="ecommerce_products",uniqueConstraints={@UniqueConstraint(name="search_idx", columns={"name", "email"})})
 */
class ECommerceProduct
{
}

使用 ORM 和框架也有助于保持 PHP 数据模型与 MySQL 模式一致,因为您将能够非常简单地生成和更新它。 See an exemple on how symfony2 can help here.

最后但并非最不重要的一点是,如果您只使用 MySQL 语句而不使用 transactions 和像 innodb 这样的引擎,您不会考虑并发访问您的数据,这可能会导致数据损坏。如果您不需要或不想为整个应用程序实现它,它的激活和兼容非事务查询非常简单。这是您应该真正考虑的 ORM 涵盖的另一个非常重要的方面。

【讨论】:

    【解决方案2】:

    首先,您构建查询的方式非常危险。您从外部来源获取原始输入,不进行任何数据验证或转义,而是直接在查询字符串中使用它。这就是 SQL 注入攻击的发生方式。

    当您使用 mysqli 时,您确实需要考虑重新实现数据库访问逻辑以使用 prepared statements,或者至少开始使用 mysqli_real_escape_string() 以使您的代码更能抵抗 SQL 注入滥用。

    至于您的特定问题,我将假设某些列或列组合必须是唯一的,而其他列不必是唯一的。对于确实需要唯一的列/组合,您可以创建指示其值不得重复的索引。例如,我将假设 AFnumber 字段是某所大学的某种识别码,对于大学表来说它必须是唯一的。如果是这种情况,那么您可以create an index 表示该字段必须是唯一的。

    CREATE UNIQUE INDEX keep_af_number_unique 
      ON university (AFnumber);
    

    有了这个约束,你就只能插入一个特定的 AF 号码一次。尝试再次插入相同的值将触发错误(您必须在代码中检查并捕获该错误!),直到您删除现有的 AFnumber 或更改其值。

    如果您有一组列,其中包含的值组合需要是唯一的,您可以跨多个列创建唯一索引

    CREATE UNIQUE INDEX multi_col_unique
      ON table_name (column1, column2, column3);
    

    现在,对于三列,一个单独的列可以多次保存相同的值,但列的组合必须是唯一的。例如,将允许以下数据:

    col1 | col2 | col3
    ===================
       1 |    1 |    1
       2 |    2 |    2
       1 |    1 |    2
    

    但如果您尝试添加具有值1, 1, 1 的另一行,则会发生错误。

    除此之外,在您的代码中实现一个系统来检测和防止多个表单提交也是一个好主意,也许通过使用存储在 PHP 会话中的令牌。 This question 有一些可能有用的解决方案。

    【讨论】:

      【解决方案3】:
      if(isset($_POST['submit']))
      {
          $degree = $_POST['degree'];
          $major = $_POST['major'];
          $univ = $_POST['univ'];
          $brevet = $_POST['brevet'];
          $baccbt = $_POST['baccbt'];
          $selectaf = $_POST['selectAF'];
      
          $sql="SELECT * FROM university,certificatesgrading WHERE AFNumber='$selectaf'";
          $result = mysql_query($sql);
          $count = count($result);
      
          if($count==0)
          {
              $sql1="INSERT INTO university (AFNumber,university.Degree,university.Major,university.Univ) VALUES('$selectaf','$degree','$major','$univ')";
              $sql2="INSERT INTO certificatesgrading (AFNumber,certificatesgrading.brevet,certificatesgrading.baccbt) VALUES('$selectaf','$brevet','$baccbt')";
              $result1 = mysql_query($sql1);
              $result2 = mysql_query($sql2);
              if(isset($result1) AND isset($result2))
              {
                  echo '<script>swal("Success", "Changes have been saved", "success");</script>';
                  redirect(base_url() . 'controller/method');//refresh header
              }
              else
              {
                  echo 'Something went wrong';
              }
          }
      
      }
      

      注意:要使用swal/sweetalert,您需要Download 并安装它 检查$_POST['degree'] 变量以大写或简单形式开头namefield

      【讨论】:

      • 此代码不会阻止多行,因为它不会考虑两个进程同时尝试插入相同数据的可能性,如果超过 1 个,您的计数检查也会失败数据库中具有相同值的行!
      • @GordonM 是的。 if($count==1)应该来if($count==0)
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-04-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-08-14
      • 2018-06-29
      • 2015-08-07
      相关资源
      最近更新 更多