PHP操作MySQL无法执行删除及多插入操作问题求助
问题排查
根本原因是所有SQL语句都赋值给同一个$sql变量,后续赋值直接覆盖前序内容,最终仅最后一条插入instant_data的SQL被执行,删除、历史表插入逻辑均未实际运行。
具体错误点
- 变量覆盖:
SensorData插入SQL、instant_data删除SQL都被后续的插入SQL覆盖,没有被调用执行 - 执行逻辑缺失:未为每条SQL单独调用
$mysqli->query()方法,仅执行了最后一次赋值的SQL - 冗余代码:存在重复的数据库连接判断逻辑,已经在开头校验过连接状态,后续无需重复判断
- 安全风险:直接拼接用户输入到SQL语句中,存在SQL注入风险,
test_input函数无法防御此类攻击
修复方案
按业务逻辑拆分SQL执行顺序,每条SQL单独执行,同时补充预处理语句和事务保证安全性与操作一致性。
if ($_SERVER["REQUEST_METHOD"] == "POST") { $serial_numb = test_input($_POST["serial_numb"]); $DHTtempC = test_input($_POST["DHTtempC"]); $DHThumid = test_input($_POST["DHThumid"]); $CCS811_CO2 = test_input($_POST["CCS811_CO2"]); $CCS811_tVOC = test_input($_POST["CCS811_tVOC"]); $PM25 = test_input($_POST["PM25"]); $PM10 = test_input($_POST["PM10"]); $reading_date = date("Y-m-d"); $update_status = test_input($_POST["update_status"]); $tipo_tabla = test_input($_POST["tipo_tabla"]); // 此处补充你原本的数据库连接代码,示例:$mysqli = new mysqli('数据库地址','账号','密码','库名'); // 检查连接 if ($mysqli->connect_error) { die("Connection failed: " . $mysqli->connect_error); } // 开启事务保证操作原子性,任意一步失败就回滚 $mysqli->begin_transaction(); try { // 第一步:执行删除操作 $del_sql = "DELETE FROM instant_data WHERE serial_numb = ?"; $del_stmt = $mysqli->prepare($del_sql); $del_stmt->bind_param("s", $serial_numb); $del_stmt->execute(); $del_stmt->close(); // 第二步:插入instant_data实时表 $instant_sql = "INSERT INTO instant_data (serial_numb, DHTtempC, DHThumid, CCS811_CO2, CCS811_tVOC, PM25, PM10, reading_date, update_status) VALUES (?,?,?,?,?,?,?,?,?)"; $instant_stmt = $mysqli->prepare($instant_sql); $instant_stmt->bind_param("sssssssss", $serial_numb, $DHTtempC, $DHThumid, $CCS811_CO2, $CCS811_tVOC, $PM25, $PM10, $reading_date, $update_status); $instant_stmt->execute(); $instant_stmt->close(); // 第三步:如果是historico类型,插入历史表SensorData if ($tipo_tabla == "historico"){ $history_sql = "INSERT INTO SensorData (serial_numb, DHTtempC, DHThumid, CCS811_CO2, CCS811_tVOC, PM25, PM10, reading_date, update_status) VALUES (?,?,?,?,?,?,?,?,?)"; $history_stmt = $mysqli->prepare($history_sql); $history_stmt->bind_param("sssssssss", $serial_numb, $DHTtempC, $DHThumid, $CCS811_CO2, $CCS811_tVOC, $PM25, $PM10, $reading_date, $update_status); $history_stmt->execute(); $history_stmt->close(); } // 所有操作成功提交事务 $mysqli->commit(); echo "New record created successfully"; } catch (Exception $e) { // 操作失败回滚所有修改 $mysqli->rollback(); echo "Error: " . $e->getMessage(); } $mysqli->close(); } else { echo "No data posted with HTTP POST."; } function test_input($data) { $data = trim($data); $data = stripslashes($data); $data = htmlspecialchars($data); return $data; }
优化说明
- 用
prepare预处理+参数绑定彻底避免SQL注入风险 - 加入事务处理,保证删除、两次插入操作的一致性,不会出现部分成功部分失败的情况
- 每条SQL单独定义变量单独执行,不会出现覆盖问题
- 严格符合业务要求的执行顺序:先删除、再插实时表、最后插历史表
内容的提问来源于stack exchange,提问作者Anna Colmenero
相关产品推荐
相关产品推荐

