在 foreach 循环中调用存储过程 - 仅第一次执行

Posted

技术标签:

【中文标题】在 foreach 循环中调用存储过程 - 仅第一次执行【英文标题】:Calling Stored Procedure in foreach loop - only first executed 【发布时间】:2011-05-16 05:02:57 【问题描述】:

这真的是my earlier question today的派生词。

我在我的数据库中创建了一个存储过程,我想从 php 中连续多次调用它。 假设这是我的程序:

CREATE PROCEDURE PROC_1(
  IN param1 VARCHAR(255),
  IN param2 VARCHAR(255))
BEGIN
  DECLARE ok INT;
  DECLARE success, failure VARCHAR(255);

  /* several SELECT, IF ... THEN, INSERT and UPDATE operations which then SET ok var to 0 or 1 */
  IF ok = 1 THEN
    SET success = 'Everything went well';
    SELECT success;
    LEAVE;
  ELSE
    SET failure = 'Problem description';
    SELECT failure;
    LEAVE;    
  END IF;
END

我是这样做的(短版):

$calls = array(
    "CALL PROC_1('param1', 'param2')",
    "CALL PROC_1('param3', 'param4')",
    "CALL PROC_1('param5', 'param6')",
);

// assuming I'm already connected to DB with $link
foreach ($calls as $i => $call)

    echo $i . ': ';
    $result = mysql_query($call);
    $ok = ($result === FALSE) ? FALSE : TRUE;
    var_dump($ok);

    if ($result !== FALSE)
        mysql_free_result($result);

第一次迭代按预期工作,但之后返回 FALSE。 这是为什么呢?

尝试mysqli 以防万一,但得到完全相同的输出:

0: bool(true)
1: bool(false)
2: bool(false)

有趣的是,我检查了 MySQL 日志(日志记录设置为记录所有查询)并且 只有第一个查询会到达服务器。下一个查询永远不会到达服务器。

PS。我正在运行 PHP 5.3.2 和 Apache 2.2.17。


更新

根据 Shakti Singh 的建议,我在查询数据库之前检查了 $link 状态。我注意到自第二次迭代以来出现了一个错误,所以这里是错误的输出:

ERROR: (0) 
0: bool(true)
ERROR: (0) 

ERROR: (0) 
1: bool(false)
ERROR: (2014) Commands out of sync; you can't run this command now

ERROR: (2014) Commands out of sync; you can't run this command now
2: bool(false)
ERROR: (2014) Commands out of sync; you can't run this command now

另外,这会出现在 MySQL 错误日志中:

101126 15:46:28 [Warning] Aborted connection 129 to db: 'db1' user: 'root' host: 'localhost' (Got an error reading communication packets)

【问题讨论】:

你能不能在 echo $i 下面 var_dump($link) 。 ': '; 这是一个很好的提示 Shakti。现在显示更多关于这个问题的信息。更新问题中的详细信息。 一个存储过程可能会返回一个以上的结果集,并且它总是会返回一个额外的结果集,该结果集不包含任何数据,但除了任何显式返回之外,还包含有关过程调用的整体错误/警告信息结果集。 - forums.mysql.com/read.php?52,228296,228347#msg-228347 现在说得通了。谢谢你的杰瑞尔。 如果您将其放入答案中,我会很乐意接受它,因为它回答了我的问题。 【参考方案1】:

在 php 中,当我们在循环中调用存储过程时,它只执行一次。当存储过程返回任何结果集时会发生这种情况。 我遇到了同样的问题。我有一个用于更新表记录的存储过程。

DELIMITER $$

DROP PROCEDURE IF EXISTS `espritkm`.`update_notification`$$
CREATE DEFINER=`root`@`localhost` PROCEDURE `update_notification`(item_id_val VARCHAR(11),item_source_val VARCHAR(50),item_type_id_val INT(50),item_type_val VARCHAR(50),created_at_val BIGINT(11),pivot_user_id_val VARCHAR(256),pivot_item_type_val VARCHAR(64),pivot_owner_type_val VARCHAR(64),pivot_owner_id_val INT(11),user_id_val VARCHAR(64),  OUT row_effect VARCHAR(11))
Begin
  Declare item_count INT(10);
   SET @SQL1 = CONCAT('select count(*) into @item_count from item_notifications where item_id = ''', item_id_val, '''');                                                                                    PREPARE S1 FROM @SQL1;                                                                                EXECUTE S1;                                                                                    DEALLOCATE PREPARE S1;     
    IF @item_count = 0 THEN
       SET @SQL2 = CONCAT('INSERT INTO item_notifications (item_id,item_source,item_type_id,item_type,created_at,pivot_user_id,pivot_item_type,pivot_owner_type,pivot_owner_id,user_id) value(''',item_id_val,''',''',item_source_val,''',''',item_type_id_val,''',''',item_type_val,''',''',created_at_val,''',''',pivot_user_id_val,''',''',pivot_item_type_val,''',''',pivot_owner_type_val,''',''',pivot_owner_id_val,''',''',user_id_val,''')');    
 PREPARE S2 FROM @SQL2;                                                                                  EXECUTE S2;                                                                                     DEALLOCATE PREPARE S2;      
      SET row_effect= "Insert";    
    ELSE             
        SET row_effect= "Update";    

    SET @SQL3 = CONCAT('UPDATE item_notifications SET viewer_id = ''',user_id_val,''' WHERE item_id = ''' ,item_id_val,'''') ;     
       PREPARE S3 FROM @SQL3;                                                                                 EXECUTE S3;                                                                                    DEALLOCATE PREPARE S3;      

    END IF;
    SELECT row_effect;
END$$

DELIMITER ;

这应该执行超过 1000 行,但只执行了一条记录。

不支持您的 SP 返回任何数据集的情况。只需消除 OUT var 或任何 select 语句(仅用于任何结果引用),它就会正常工作。

【讨论】:

【参考方案2】:

一个存储过程可能会返回多个结果集,并且它总是会返回一个额外的结果集,该结果集不包含任何数据,但除了任何显式返回的结果集之外,还包含有关过程调用的整体错误/警告信息。

来源 - http://forums.mysql.com/read.php?52,228296,228347#msg-228347

【讨论】:

以上是关于在 foreach 循环中调用存储过程 - 仅第一次执行的主要内容,如果未能解决你的问题,请参考以下文章

Perl 执行 DBI 循环执行

使用 forEach 时避免回调多次调用

oracle存储过程中循环调用存储过程

#189 stat(动态规划)

mybatis 注解写法 多层嵌套foreach,调用存储过程,批量插入数据

ORACLE 11G在存储过程里面遍历游标, 调用job任务定时运行