使用PHP在Mysql中插入语句后重复记录

使用PHP在Mysql中插入语句后重复记录,php,mysql,session,insert,duplicates,Php,Mysql,Session,Insert,Duplicates,今天我为我的一个客户发布了一个新的应用程序,一个INSERT语句出现了一些不正常的情况。 在测试过程中,我们没有遇到类似的情况,我不确定这是因为有很多用户同时访问(100个用户),还是与其他内容有关。 因此,在1次插入之后,它在数据库表中插入了1条记录以及其他一些2-3个副本…我没有使用事务,这是否可以解决此问题?下面您可以找到我的代码和带有事务的代码,以防这是解决方案。 非常感谢你的帮助 $submit_the_bill = "INSERT INTO bill_status (`bill_st

今天我为我的一个客户发布了一个新的应用程序,一个INSERT语句出现了一些不正常的情况。 在测试过程中,我们没有遇到类似的情况,我不确定这是因为有很多用户同时访问(100个用户),还是与其他内容有关。 因此,在1次插入之后,它在数据库表中插入了1条记录以及其他一些2-3个副本…我没有使用事务,这是否可以解决此问题?下面您可以找到我的代码和带有事务的代码,以防这是解决方案。 非常感谢你的帮助

$submit_the_bill = "INSERT INTO bill_status
(`bill_status_bill_id`,`bill_status_username`, `bill_status_phone_number`, `bill_status_status`,`bill_paid`, `deduction`)
VALUES ('".$bill_id."', '".$_SESSION['username']."', '".$_SESSION['phone_number']."','1','0','".$deduction."')";
$submit_the_bill_result = $conn->query($submit_the_bill);

//TRANSACTION STARTS HERE
try {
$conn->autocommit(FALSE);
$submit_the_bill = "INSERT INTO bill_status
(`bill_status_bill_id`,`bill_status_username`, `bill_status_phone_number`, `bill_status_status`,`bill_paid`, `deduction`)
VALUES ('".$bill_id."', '".$_SESSION['username']."', '".$_SESSION['phone_number']."','1','0','".$deduction."')";
$submit_the_bill_result = $conn->query($submit_the_bill);
$conn->commit();
} catch (Exception $e) {
// An exception has been thrown
// We must rollback the transaction
$conn->rollback();
}
这是一个完整的页面,信息来自上一页的表单,并在执行查询和发送电子邮件后转到主页。有什么想法吗

<?php session_start();

require('include/config.php'); //database connection

require "PHPMailer/PHPMailerAutoload.php";

$bill_id = $_POST['bill_id'];
$user_phone_number = $_POST['user_phone_number'];
$deduction = $_POST['deduction'];

$net_value_hidden = round($_POST['net_value_hidden'],2);
$official_cost_hidden = round($_POST['official_cost_hidden'],2);
$personal_cost_hidden = round($_POST['personal_cost_hidden'],2);
$tax_hidden = round($_POST['tax_hidden'],2);
$total_hidden = round($_POST['total_hidden'],2);
$total_private_price_with_vat = ($personal_cost_hidden/100)*20;
$total_private_price_with_vat = round($total_private_price_with_vat,2);
$total_payable_ammount = round($personal_cost_hidden + $total_private_price_with_vat,2);

if($total_hidden == 0) {$deduction = 4;}

if($deduction == 1) {$deduction_email = "Salary";}
else if($deduction == 2) {$deduction_email = "Cash";}
else if($deduction == 3) {$deduction_email = "Bank Transfer";}
else {$deduction_email = "No deduction";}

$submit_the_bill = "INSERT INTO bill_status
(`bill_status_bill_id`,`bill_status_username`, `bill_status_phone_number`, `bill_status_status`,`bill_paid`, `deduction`)
VALUES ('".$bill_id."', '".$_SESSION['username']."', '".$_SESSION['phone_number']."','1','0','".$deduction."')";
$submit_the_bill_result = $conn->query($submit_the_bill);

$sql_smtp = "SELECT * FROM smtp_settings";
$result_smtp = $conn->query($sql_smtp);
if ($result_smtp->num_rows > 0) {   
    while($row = $result_smtp->fetch_assoc()) {
        $smtp_host = $row['smtp_server'];
        $smtp_username = $row['smtp_user_email'];
        $smtp_password = $row['smtp_user_password'];
        $smtp_ssl = $row['smtp_ssl'];
        $smtp_port = $row['smtp_port'];
    }
}
if ($smtp_ssl == 1) {$smtp_ssl = "ssl";} else {$smtp_ssl = "tls";}

$mail = new PHPMailer;

$mail->isSMTP();                                      // Set mailer to use SMTP
$mail->Host = $smtp_host;  // Specify main and backup SMTP servers
$mail->SMTPAuth = true;                               // Enable SMTP authentication
$mail->Username = $smtp_username;                 // SMTP username
$mail->Password = $smtp_password;                           // SMTP password
$mail->SMTPSecure = $smtp_ssl;                            // Enable TLS encryption, `ssl` also accepted
$mail->Port = $smtp_port;                                    // TCP port to connect to

$mail->setFrom('email@example.com', 'Email');
$mail->addAddress($_SESSION['username']);               // Name is optional
$mail->isHTML(true);                                  // Set email format to HTML

$mail->Subject = $_SESSION['username']." submitted new bill - ".$_SESSION['bill_period'];
$mail->Body    = $_SESSION['username']."(".$_SESSION['phone_number'].") Submit New Bill - ".$_SESSION['bill_period']." <br/><br/>";

$mail->AltBody = $_SESSION['username']."(".$_SESSION['phone_number'].") Submit New Bill - ".$_SESSION['bill_period']." <br/><br/>";

if(!$mail->send()) {
    echo 'Message could not be sent.';
    echo 'Mailer Error: ' . $mail->ErrorInfo;
} else {
    //echo 'E-mail sent';
}
unset($_SESSION['bill_period']);
$conn->close();

header("Location:location"); //going to the home page

?> 

我对交易解决您的问题并不乐观。我认为问题在于代码执行了不止一次,如果封装在一个事务中,那么只需使用事务运行两个查询,而不是使用自动提交运行两个查询

为什么代码要运行两次?这不能用你问题中的信息来回答。我们只能猜测

很可能是重复的插入请求,要么是在人工端(点击刷新,因为它花费的时间太长,要么是因为他们重新启动了chrome并重新打开了选项卡,或者是因为其他原因),要么是在负载平衡器端(重试失败的请求),要么是在ajax调用或其他方面

或者,您的工作流可能会促使多人执行相同的操作。例如,如果有多个人拉“最上面的账单”,查看它,然后将其标记为完成,您需要在应用程序中执行一些操作,以确保他们不会在大致相同的时间对相同的记录进行操作

值得深入研究日志和数据行,并验证对insert web端点的请求数是否与您所想的一致,以及每个“重复插入”中的数据实际上完全相同


您的修复方法很可能取决于原因和您的业务逻辑。您可以使用其他表“签出”特定用户的账单ID,以确保同一账单不会被插入两次。您可以为插入请求提供一个ID,这样就可以有效地消除重复发送两次相同的插入(最后一次插入在电子商务中几乎每个购物车结账过程中都会实现,否则刷新会再次购买您的物品或重新启动不完整的支付过程!)

如果没有sql注入漏洞,那就太接近了。你真的应该使用准备好的语句将数据安全地插入到查询中。那么,为什么要运行两次查询?我认为这只是两个单独的代码示例挤在一起。第二个是我的建议,它不在代码中。。。这能解决问题吗?谢谢你的回答,我只是想找到一个解决方案。为什么你没有一个唯一的索引来防止重复插入呢?其次,交易与防止重复无关。第三,仅仅显示insert语句并不能帮助我们解决您的问题。您需要理解的是,为什么同一个insert被多次调用。