PHP mysqli_multi_query 在while循环中的事务
Posted
技术标签:
【中文标题】PHP mysqli_multi_query 在while循环中的事务【英文标题】:PHP mysqli_multi_query transaction in while loop 【发布时间】:2017-01-03 15:39:32 【问题描述】:需要将数据从现有表迁移到两个相同的表。原始数据在插入两个新表之前需要解析。 (该代码未显示,因为我希望隔离此问题。) 想使用事务来确保新表是相同的。
task_id 字段在 test_timecard 中是自增字段,在 test_timecar_2 中是 unsigned mediumint。
Engine 是两个表的 InnoDB。
单独查询有效:
$timecard_data_results = array();
$fill_old_data_array_def = " SELECT task_id, company_id, employee_id, location, task_name, task_start_time, task_end_time, tccomment FROM timecard WHERE company_id = '" . $company_request . "' AND employee_id = '" . $employee_request . "' AND DATE(task_start_time) < '" . $new_text_format_date . "' AND (DATE(task_end_time) > '2014-12-31' OR DATE(task_end_time) = '2000-01-01') ORDER BY task_start_time";
$timecard_data_results = mysqli_query($conn, $fill_old_data_array_def);
while($timecard_record = mysqli_fetch_assoc($timecard_data_results))
$company_id = $timecard_record['company_id'];
$employee_id = $timecard_record['employee_id'];
$location = $timecard_record['location'];
$task_name = $timecard_record['task_name'];
$task_start_time = $timecard_record['task_start_time'];
$task_end_time = $timecard_record['task_end_time'];
$tccomment = $timecard_record['tccomment'];
$troubleshoot_def = "INSERT INTO test_timecard (company_id, employee_id, location, task_name, task_start_time, task_end_time, tccomment) VALUES ('" . $company_id . "', '" . $employee_id . "', '" . $location . "', '" . $task_name . "', '" . $task_start_time . "', '" . $task_end_time . "', '" . $tccomment . "')";
$troubleshoot_2_def = "INSERT INTO test_timecard_2 (task_id, company_id, employee_id, location, task_name, task_start_time, task_end_time, tccomment) VALUES (LAST_INSERT_ID(), '" . $company_id . "', '" . $employee_id . "', '" . $location . "', '" . $task_name . "', '" . $task_start_time . "', '" . $task_end_time . "', '" . $tccomment . "')";
$troubleshoot = mysqli_query ($conn, $troubleshoot_def);
$troubleshoot_2 = mysqli_query ($conn, $troubleshoot_2_def);
与 mysqli_multi_query 的事务仅在两个表中插入一行。未报告任何错误。
$timecard_data_results = array();
$fill_old_data_array_def = " SELECT task_id, company_id, employee_id, location, task_name, task_start_time, task_end_time, tccomment FROM timecard WHERE company_id = '" . $company_request . "' AND employee_id = '" . $employee_request . "' AND DATE(task_start_time) < '" . $new_text_format_date . "' AND (DATE(task_end_time) > '2014-12-31' OR DATE(task_end_time) = '2000-01-01') ORDER BY task_start_time";
$timecard_data_results = mysqli_query($conn, $fill_old_data_array_def);
while($timecard_record = mysqli_fetch_assoc($timecard_data_results))
$company_id = $timecard_record['company_id'];
$employee_id = $timecard_record['employee_id'];
$location = $timecard_record['location'];
$task_name = $timecard_record['task_name'];
$task_start_time = $timecard_record['task_start_time'];
$task_end_time = $timecard_record['task_end_time'];
$tccomment = $timecard_record['tccomment'];
$troubleshoot_def = "START TRANSACTION; INSERT INTO test_timecard (company_id, employee_id, location, task_name, task_start_time, task_end_time, tccomment) VALUES ('" . $company_id . "', '" . $employee_id . "', '" . $location . "', '" . $task_name . "', '" . $task_start_time . "', '" . $task_end_time . "', '" . $tccomment . "'); INSERT INTO test_timecard_2 (task_id, company_id, employee_id, location, task_name, task_start_time, task_end_time, tccomment) VALUES (LAST_INSERT_ID(), '" . $company_id . "', '" . $employee_id . "', '" . $location . "', '" . $task_name . "', '" . $task_start_time . "', '" . $task_end_time . "', '" . $tccomment . "'); COMMIT;";
$troubleshoot = mysqli_multi_query ($conn, $troubleshoot_def);
难倒。
【问题讨论】:
如果你打算使用 mysqli_multi_query(),那么它应该只被调用一次(在循环之外),当所有的 INSERT 语句被连接时。这也意味着 START TRANSACTION 必须在循环之前移出并在循环之后移出 COMMIT,尽管它们并不是真正需要的。回显查询字符串以确定是否填充了所有所需的语句。也检查以下相关问题:***.com/q/20143592/2298301 【参考方案1】:$troubleshoot_def = "INSERT INTO test_timecard (company_id, employee_id, location, task_name, task_start_time, task_end_time, tccomment) VALUES ('" . $company_id . "', '" . $employee_id . "', '" . $location . "', '" . $task_name . "', '" . $task_start_time . "', '" . $task_end_time . "', '" . $tccomment . "')";
$troubleshoot_2_def = "INSERT INTO test_timecard_2 (task_id, company_id, employee_id, location, task_name, task_start_time, task_end_time, tccomment) VALUES (LAST_INSERT_ID(), '" . $company_id . "', '" . $employee_id . "', '" . $location . "', '" . $task_name . "', '" . $task_start_time . "', '" . $task_end_time . "', '" . $tccomment . "')";
这里有很多问题。首先,将几乎相同的数据插入到两个不同的表中根本没有任何意义。事实上,当操作完成时,您将拥有三个具有几乎相同数据的表,即 test_timecard_2
、test_timecard
和 timecard
其次,您要插入未转义的数据。由于数据来自您的另一个表,因此 sql 注入的可能性不大,但查询仍有可能失败。具体来说,我在谈论这样的代码:
VALUES ('" . $company_id . "', '" . $employee_id . "', '" . $location . "', '" . $task_name . "', '" . $task_start_time . "', '" . $task_end_time . "', '" . $tccomment . "')";
第三,您几乎不需要执行 SELECT - LOOP - INSERT,因为 mysql 有一个内置的 INSERT SELECT 命令。
INSERT INTO test_timecard (company_id, employee_id, location, task_name, task_start_time, task_end_time, tccomment)
SELECT * FROM time_card
注意列正确(上面只是从您的代码的两个部分复制粘贴)
【讨论】:
抱歉误导。子表实际上会有一些父表中不存在的附加字段,因此使用 while 循环来解析原始数据。当我遇到事务问题时,我试图在不干扰我的问题中其他代码的情况下隔离那个混乱。创建新表是一次性过程,完全由内部人员完成,因此无需担心注入问题。 一些额外的字段不足以成为创建这些额外表格的充分理由。这违反了所有数据库规范化原则。 撇开额外表的问题,正确的方法是使用单个 INSERT SELECT 语句。而不是根据表的大小可能会产生数千或数百万个插入 感谢您的关注。数据库设计。在插入新表之前,我需要在一系列 if 语句中调整原始数据。同时,有必要将原始数据的副本存档在永远不会用于查询等的第二个表中。新表在很多方面与原始表不同,但我认为最清楚的是从原始帖子中提供的代码,因此重点将放在 while 循环内的事务使用上。从 Dhruv Saxena 的评论看来,我需要为插入创建另一个 php 数组。 不幸的是,这被证明是一个红鲱鱼。以上是关于PHP mysqli_multi_query 在while循环中的事务的主要内容,如果未能解决你的问题,请参考以下文章
如果不使用 mysqli_multi_query,SQL 注入将无法工作
我收到一个错误“命令不同步;当我使用mysqli_multi_query时,你现在无法运行此命令