微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

错误Prepared statement需要重新准备

如何解决错误Prepared statement需要重新准备

我正在为一个业余 PHP 网站 (PHP 7.3.27-1~deb10u1 (fpm-fcgi)) 运行 MariaDB 服务器 (10.3.27-MariaDB-0+deb10u1 Raspbian 10)。

昨天我决定是时候开始每天备份数据库并为此目的在 cron 作业中添加脚本了。在今晚运行 cron 作业后,网站给了我这个错误

Fatal error: Uncaught MysqLi_sql_exception: Prepared statement needs to be re-prepared in [a].PHP:180 
Stack trace: 
#0 [a].PHP(180): MysqLi_stmt->execute() 
#1 [b].PHP(64): getTargetID(Object(MysqLi),'ha',2020) 
#2 [c].PHP(3): require('....') 
#3 {main} thrown in funcs.PHP on line 180

函数 getTargetID() 基本上是执行一个从视图返回 ID 的查询。在 TablePlus 中运行完全相同的查询(针对同一个数据库)工作正常。

如果我重新启动 MariaDB 服务器,PHP 代码会再次按预期执行,直到再次运行备份脚本。

备份脚本基本上是这样的:

MysqLdump -u ${USER} -h${HOST} -p${PASSWORD} --all-databases |gzip > ${sqlFILE}$

编辑:MysqLdump 命令放置在 shell 脚本 (db_backup.sh) 中,并在午夜使用 cron 作业执行。

该脚本在备份机上执行,该备份机具有以下权限的数据库用户

  • 选择
  • 触发
  • 显示视图
  • 锁表

编辑 2:

导致错误函数包含以下代码

function getTargetID(&$MysqLi,$league,$year) {
  $sql_query = <<<sql
  SELECT team_id
  FROM standings

  WHERE league = ? and season = ?
  ORDER BY points DESC,goals_for DESC,team_name
  LIMIT 1;
sql;

  $stmt = $MysqLi->prepare($sql_query);
  $stmt->bind_param("si",$year); 
  $stmt->execute();
  $result = $stmt->get_result();

  if ($result->num_rows > 0) {
    $rows = $result->fetch_all(MysqLI_ASSOC);
    $team_id = $rows[0]["team_id"];
    $result->free();
    return $team_id;
  }
  else { echo "<!-- Error 107 -->"; }
  $stmt->close();
}

Standings 是一种“输出”足球联赛积分表的视图。

我有点不知该如何解决这个问题,到目前为止我还无法通过 Google 找到任何解决方案。应该在转储命令中添加一些东西吗?

解决方法

看看这个......

    $stmt = $mysqli->prepare($sql_query);
    $stmt->bind_param("si",$league,$year);
    $stmt->execute();
    $result = $stmt->get_result();
    if ($result->num_rows > 0) {
      /* do some stulff
      $rows = $result->fetch_all(MYSQLI_ASSOC);
      $team_id = $rows[0]["team_id"];
      $result->free();
      return $team_id;                   /* return here */
    }
    else { echo "<!-- Error 107 -->"; }
    $stmt->close();                      /*  close here */

当您的查询成功时,您无需先关闭准备好的查询对象即可从函数中返回。是否有可能导致某种形式的准备查询泄漏?

尝试将 php 代码更改为这样的....

    $stmt = $mysqli->prepare($sql_query);
    $stmt->bind_param("si",$year);
    $stmt->execute();
    $result = $stmt->get_result();
    if ($result->num_rows > 0) {
      /* do some stulff
      $rows = $result->fetch_all(MYSQLI_ASSOC);
      $team_id = $rows[0]["team_id"];
      $result->free();
      $stmt->close();                    /* close first */ 
      return $team_id;                   /* return here */
    }
    else { echo "<!-- Error 107 -->"; }
    $stmt->close();

在开始测试之前sudo shutdown -r now您的机器是明智之举。这样,我们就可以确保开始时不会潜伏在无名缓存中的准备好的查询。

测试需要一两个备份周期。

如果这确实解决了您的问题,那么这个特定的 mysqli 边缘情况会抛出不正确(不够细致)的错误消息。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。