如何防止使用PDO重复记录插入

时间:2015-02-13 16:44:10

标签: php html sql-server pdo

我想尝试设置一些内容,如果用户已经提交了dept密钥和当前日期,它将停止插入记录。如果输入重复记录,则会发出错误。

以下是我的插入页面的一部分,但它无法正常工作

$stmt= $db->prepare("INSERT INTO tbl_lighting(Department, 
    areaCode, offtime, gytime, ftime, ini, 
    sat_ob_department, sat_ib_department,
    sat_ob_onTime,sat_ib_onTime,
    sat_ob_offTime, sat_ib_offTime,
    ob_signature,ib_signature, 
    deptkey, comments,ib_comments,ob_comments,Requestdate

 ) Values (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)WHERE NOT EXISTS 
(SELECT * FROM tbl_lighting where deptkey = $deptkey AND Requestdate= CAST(GETDATE() AS DATE)");

$stmt->bindParam(1, $_POST["Department"]);
$stmt->bindParam(2, $_POST["areaCode"]);
$stmt->bindParam(3, $_POST["offtime"]);
$stmt->bindParam(4, $_POST["gytime"]);
$stmt->bindParam(5, $_POST["ftime"]);
$stmt->bindParam(6, $_POST["ini"]);
$stmt->bindParam(7, $_POST["sat_ob_department"]);
$stmt->bindParam(8, $_POST["sat_ib_department"]);
$stmt->bindParam(9, $_POST["sat_ob_onTime"]);
$stmt->bindParam(10, $_POST["sat_ib_onTime"]);
$stmt->bindParam(11, $_POST["sat_ob_offTime"]);
$stmt->bindParam(12, $_POST["sat_ib_offTime"]);
$stmt->bindParam(13, $_POST["ob_signature"]);
$stmt->bindParam(14, $_POST["ib_signature"]);
$stmt->bindParam(15, $_POST["deptkey"]);
$stmt->bindParam(16, $_POST["comments"]);
$stmt->bindParam(17, $_POST["ib_comments"]);
$stmt->bindParam(18, $_POST["ob_comments"]);
$stmt->bindParam(19, $_POST["Requestdate"]);


$stmt->execute();

这是我提交的表格

<form action = "insert_process.php" onsubmit="return validateForm()" name="form" id="form" method ="post" class="style1">

<table align="center" id="tfhover" class="tftable" border="1">
<br><br>
<tr>
<td colspan="7"><h1 align="center">Lighting Schedule Form</h1></td>
</tr>

<tr>
<th>Department</th><th style="width: 75px">Area Code</th><th style="width: 144px">Off Time</th><th>Grave Yard On Time</th><th>First Shift OnTime</th><th width="125px">Comments Or Date By</th><th>Initials</th></tr>

<tr>

    <!--First row accross on the table-->
<td><select name="Department" id="Department" >
            <option value ="">Please select ...</option>
            <option value ="Upstairs Hang East">Upstairs Hang East</option>
            <option value ="Upstairs Hang West">Upstairs Hang West</option>
            <option value ="RDR">RDR</option>
            </select></td>
<td style="width: 75px"><input id="areaCode" name="areaCode" onkeydown="return false;" type="text"/></td>
<td style="width: 144px"><input class="offtime" id="offtime" name="offtime"  type="text" /></td>
<td><input id="gytime" name="gytime" type="text"></td>
<td><input id="ftime" name="ftime" type="text" ></td>
<td><input id="comments" name="comments" type="text"></td>
<td><input id="ini" name="ini" type="text" style="width: 68px" /></td>
</tr>


<input id="deptkey" name="deptkey" onkeydown="return false;" type="hidden"/>

    <!--end-->

2 个答案:

答案 0 :(得分:2)

问题的实质是停止重复记录,我将解释为什么使用PDO的唯一密钥和异常是正确的方法。

数据库维护关系并存储数据。数据库的一个工作是处理并发和存储数据。防止数据库中的重复记录是通过创建唯一键来处理的,因此不允许在数据模型中出现这样的记录。数据库处理多个同时连接的用户,而这些用户又会插入一些数据。

我看到人们在做的是选择一条记录,然后检查它是否存在以及是否返回0行 - 它们继续进行插入。这是一种糟糕的方法,它不仅会损害性能,而且通常无法防止重复记录。原因是因为PHP(或任何语言)与MySQL服务器(或任何其他数据库服务器)之间存在轻微延迟。当您选择数据并完成检查时,已经过了少量时间 - 比如说1毫秒。在此期间,另一个用户可能已连接并经历了相同的过程(选择,检查是否为0行,如果为0则插入)。由于这两个用户同时做同样的事情,两者都会得到关于结果的信息 - 因为PHP进程和MySQL之间的微小延迟。反过来,您最终可能会有重复的记录。您还花时间选择一些内容并通过套接字连接发送它。

让数据库处理所有工作要快得多。由于独特的约束不能进行插入,因此您只需插入并使插入失败就会更容易(它比选择和检入PHP要少得多,而且价格昂贵)。数据库还同时处理并发或多个用户&#34;。这意味着您的数据库知道其数据的状态,如果您继续这样做,它是最好的。你最终也会得到更少的代码。

你的算法应该是这样的:

  • 获取输入
  • 准备声明
  • 执行插入
  • 如果异常上升,则会有重复的记录(您可以检查数据库返回的代码,以确保它是因为重复的密钥或其他原因)

弗雷德在评论中说的是正确的,也是唯一正确防止重复插入的正确方法。此外,由于您使用的是预准备语句,因此无需在语句中指定任何变量。只需绑定所有内容,让PDO负责清理用户输入。

答案 1 :(得分:0)

也许你必须像这样逃避你的php变量$ deptkey,并像这样大写WHERE条件:


$stmt= $db->prepare("INSERT INTO tbl_lighting(Department, 
    areaCode, offtime, gytime, ftime, ini, 
    sat_ob_department, sat_ib_department,
    sat_ob_onTime,sat_ib_onTime,
    sat_ob_offTime, sat_ib_offTime,
    ob_signature,ib_signature, 
    deptkey, comments,ib_comments,ob_comments,Requestdate

) Values (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)WHERE NOT EXISTS (SELECT * FROM tbl_lighting WHERE deptkey = '".$deptkey."' AND Requestdate= CAST(GETDATE() AS DATE)");