如何解决Mysqli使用AJAX POST到PHP文件的预准备语句用法
我的问题是,PHP MysqLi准备的语句的效率如何?从我的基础阅读中了解到,准备好的语句1)使用绑定输入来帮助安全2)通过某种程度地“预打包”或“准备” SQL查询来加速和“减少”发送到服务器的数据,一旦有数据可用,它就将数据附加到准备好的语句上并执行它。这也有助于在重复插入相同数据(不同值)时“重复”使用同一语句,因为该语句仅准备一次。
现在,我正在构建一个具有多个功能的网站,并且所有(或大多数)功能都使用JQuery和AJAX来获取用户输入,进行一些检查(在JS / JQ或PHP中),发送数据到AJAX URL中指定的PHP文件PHP_AJAX_Handler.PHP。 PHP文件准备sql statemtns以将数据插入数据库,然后返回JSON成功/失败消息。例如,我的大多数功能都按如下编程;以下是我正在使用的一个文件:1)检查现有的洲际国家/地区对,以及2)插入新的洲际国家/地区对。
HTML:
<input type='text' id='continent'>
<input type='text' id='country'>
<button id='btn1'></button>
<p id='p1'></p>
<p id='p2'></p>
<p id='p3'></p>
jQuery:
$("#btn1")click(function(){
var Cntt = $("#continent").val();
var Ctry = $("#country").val();
$.post("PHP_AJAX_Handler.PHP",{CN:cntt,CT:ctry},function(DAT)
{ var RET_j = json.PARSE(dat);
if(RET_j.PASS=='FAIL')
{ $('#p1').html(RET_j.PASS);
$('#p2').html(RET_j.MSG1);
}
if(RET_j.PASS=='OKAY')
{ $('#p1').html(RET_j.PASS);
$('#p3').html(RET_j.MSG2);
} }
);
});
<?PHP
session_start();
if( (isset($_POST['CT'])) && (isset($_POST['CN'])))
{ require_once ("golin_2.PHP");
$CN = $_POST['CN'];
$CT = $_POST['CT'];
$ER = "";
$CONN = MysqLi_connect($SERVER,$USER,$PASS,$dbnAME);
If($CONN == FALSE)
{ $ER = $ER . "Err: Conn Could not connect to Databse ".MysqLi_connect_errno().' '.MysqLi_connect_error();
}
else
{ $sql_1 = "SELECT * FROM sailors.continental_regions WHERE CONTINENT = ? AND COUNTRY = ?";
if(!($STMT_1 = MysqLi_stmt_init($CONN)))
{ $ER = $ER . "Err: Stmt Prepare Failed";
}
else
{ if(!MysqLi_stmt_prepare($STMT_1,$sql_1)) ///FirsT SET of prepared statement lines
{ $ER = $ER . "Err: Stmt Prepare Failed";
}
else
{ if(!MysqLi_stmt_bind_param($STMT_1,"ss",$CN,$CT))
{ $ER = $ER . "Err: Stmt Prepare Failed";
}
else
{ if(!(MysqLi_stmt_execute($STMT_1)))
{ $ER = $ER . "Err: Stmt_1 Execute Failed";
}
else
{ $RES_1 = MysqLi_stmt_get_result($STMT_1);
$NUMROWS_1 = MysqLi_num_rows($RES_1);
if($NUMROWS_1>0)
{ $ER = $ER . "Err: duplicate '$CN' '$CT' pair";
}
if($NUMROWS_1==0)
{ $sql_2 = "INSERT INTO DB.continental_regions (CONTINENT,COUNTRY) values (?,?)";
if(!($STMT_2=(MysqLi_stmt_init($CONN))))
{ $ER = $ER . "Err: Init2 Failed";
}
else
{ if(!MysqLi_stmt_prepare($STMT_2,$sql_2)) ///SECOND SET of prepared statement lines
{ $ER = $ER . "Err: Prep2 Failed".MysqLi_error($CONN);
}
else
{ if(!MysqLi_stmt_bind_param($STMT_2,$CT))
{ $ER = $ER . "Err: Bind2 Failed";
}
else
{
if(!(MysqLi_stmt_execute($STMT_2)))
{ $ER = $ER . "Err: Exec Failed";
}
else
{ $arr['PASS'] = 'OK';
}
}
}
}
}
}
}
}
}
MysqLi_free_result($RES_1);
MysqLi_stmt_close($STMT_1);
MysqLi_stmt_close($STMT_2);
MysqLi_close($CONN);
}
if($ER!=="")
{ $arr['MSG'] = $ER;
$arr['PASS'] = 'FAIL';
}
if($arr['PASS']=="OK")
{ $arr['MSG2'] = "Insert Success";
}
echo json_encode($arr);
}
else
{ header("location: ../Error_Fail.PHP");
}
?>
如您所见,PHP文件变得相当长。有一组准备语句用于检查表中是否已存在CC对,然后提供另一组语句来插入CC对。 从我所看到的,对于每个添加新值对的AJAX请求,将再次准备MysqLi语句。然后再次用于下一个请求,依此类推。我想这只是为了实现安全性而给服务器造成大量开销和数据。这对于使用AJAX-POST-PHP开发Web应用程序的其他人是否正确?对我来说,每次准备似乎都不可避免地只能插入一次值?当数据可用时,如何处理一次准备该语句,并且仅重复执行一次?我似乎无法理解准备好的陈述的“效率”因素。
谢谢..我们将感谢一些经验丰富的程序员的建议。
解决方法
您说:
如您所见,PHP文件变得相当长。
是的,但这不是准备好的语句的错。您一定已经从一篇写得不好的教程中学习了PHP开发。此代码不必太长。实际上,它可以大大缩短。
仅修复现有代码即可使其更具可读性。我使用了OOP风格的mysqli,并删除了所有这些if
语句。您应该改为启用错误报告。
<?php
session_start();
if (isset($_POST['CT'],$_POST['CN'])) {
require_once "golin_2.php";
$CN = $_POST['CN'];
$CT = $_POST['CT'];
$ER = "";
$arr = [
'PASS' => "OK",'MSG2' => "Insert Success",]; // successful state should be the default outcome
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
$CONN = new mysqli($SERVER,$USER,$PASS,$DBNAME);
$CONN->set_charset('utf8mb4'); // always set the charset
// To check existance of data in database we use COUNT(*)
$stmt = $CONN->prepare("SELECT COUNT(*) FROM sailors.continental_regions WHERE CONTINENT = ? AND COUNTRY = ?");
$stmt->bind_param("ss",$CN,$CT);
$stmt->execute();
$NUMROWS = $stmt->get_result()->fetch_row()[0];
if ($NUMROWS) {
$ER .= "Err: duplicate '$CN' '$CT' pair";
} else {
$stmt = $CONN->prepare("INSERT INTO DB.continental_regions (CONTINENT,COUNTRY) values (?,?)");
$stmt->bind_param("ss",$CT);
$stmt->execute();
}
if ($ER) {
$arr = [
'PASS' => "FAIL",'MSG' => $ER,];
}
echo json_encode($arr);
} else {
header("location: ../Error_Fail.php");
}
如果表的这两列上都有一个复合UNIQUE键,则可以删除select语句。另外,您应该清理响应准备。成功状态应为默认状态,并且只有在出现问题时才应将其替换为错误消息。
在此示例中,我删除了一条SQL语句。整个过程现在变得简单得多。
<?php
define('DUPLICATE_KEY',1062);
session_start();
if (isset($_POST['CT'],$_POST['CN'])) {
require_once "golin_2.php";
$CN = $_POST['CN'];
$CT = $_POST['CT'];
$arr = [
'PASS' => "OK",$DBNAME);
$CONN->set_charset('utf8mb4'); // always set the charset
try {
$stmt = $CONN->prepare("INSERT INTO continental_regions (CONTINENT,$CT);
$stmt->execute();
} catch (mysqli_sql_exception $e) {
if ($e->getCode() !== DUPLICATE_KEY) {
// if it failed for any other reason than duplicate key rethrow the exception
throw $e;
}
// if SQL failed due to duplicate entry then set the error message
$arr = [
'PASS' => "FAIL",'MSG' => "Err: duplicate '$CN' '$CT' pair",];
}
echo json_encode($arr);
} else {
header("location: ../Error_Fail.php");
}
关于性能。
在此示例中,性能没有问题,并且准备好的语句不会提高或降低性能。我假设您正在尝试将性能与静态SQL查询进行比较,但是在您的简单示例中,应该没有任何区别。当您需要多次执行同一条SQL时,与静态查询相比,准备好的语句可以使您的代码更快。
如果发现每次编写3行代码的次数过多,则可以创建一个包装器函数,将其简化为一个函数调用。公平地说,您应该避免单独使用mysqli。要么切换到PDO,要么在mysqli周围使用某种抽象库。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。