首页 > 解决方案 > mysql INSERT 失败但未抛出错误:max_allowed_pa​​cket:设置显示冲突结果

问题描述

我通过 _POST 成功地将数据接收到服务器客户端帐户,但是当行数据高于 ~25MB 时,我无法将数据插入到包含 longblob 类型的行表中。我看不到 php 准备好的语句/文件引发的任何错误,php 文件正常关闭。我正在检查我的 max_allowed_pa​​cket 是否配置正确。

我没有服务器 root 权限和访问权限,我看不到 my.cnf,我正在与我的主机交谈以确保客户端和服务器 max_allowed_pa​​cket都设置为 256M。

php 文件插入部分:

$itemAttributes=$_POST['itemAttributes'];
$itemName=$_POST['itemName'];

if(!($stmt = $conn->prepare("INSERT INTO $itemTable (`itemName`, `itemAttributes`) VALUES (?, ?)")))
        echo "<br/>Failed to Prepare";
        else
          echo "<br/>Prepare success.";  

$stmt->execute([$itemName,$itemAttributes]);
          echo " Success executing";

$conn->connection=null;
if($conn->connection==null)
  echo "<br />Connection Closed.......";

这些是我正在做的检查,我是否遗漏了任何以确保 max_allowed_pa​​cket 不会在其他地方被覆盖并且在所有地方都正确设置?

客户端设置检查:所有这三个检查给我 256MB max_allowed_pa​​cket:

mysql SHOW VARIABLES LIKE 'max_allowed_packet' 
mysql SHOW GLOBAL VARIABLES LIKE 'max_allowed_packet'
mysql SHOW SESSION VARIABLES LIKE 'max_allowed_packet'

但是,我成功登录到 mysql 命令提示符(mysql --user userName --password databaseName)检查 max_allowed_pa​​cket 但它显示为 NULL,这是什么意思?

mysql> select @max_allowed_packet;
+---------------------+
| @max_allowed_packet |
+---------------------+
| NULL                |
+---------------------+
1 row in set (0.00 sec)

服务器设置检查:如何检查 GLOBAL 和 SESSION 的服务器“max_allowed_pa​​cket”?我尝试将上面的“mysql”替换为“mysqld”,但没有得到任何结果和警告,我无法与“max_allowed_pa​​cket”的大小相关:

[useraccount@cloud ~]$ mysqld SHOW GLOBAL VARIABLES LIKE 'max_allowed_packet'
2020-02-12T07:47:33.832292Z 0 [Warning] Could not increase number of max_open_files to more than 1024 (request: 65536)
2020-02-12T07:47:33.832480Z 0 [Warning] Changed limits: max_connections: 214 (requested 256)
2020-02-12T07:47:33.832487Z 0 [Warning] Changed limits: table_open_cache: 400 (requested 2000)
2020-02-12T07:47:33.945335Z 0 [Warning] TIMESTAMP with implicit DEFAULT value is deprecated. Please use --explicit_defaults_for_timestamp server option (see documentation for more details).
2020-02-12T07:47:33.945476Z 0 [Warning] Can't create test file /var/lib/mysql/cloud.lower-test
2020-02-12T07:47:33.945569Z 0 [Note] mysqld (mysqld 5.7.29) starting as process 75 ...
2020-02-12T07:47:33.947615Z 0 [Warning] Can't create test file /var/lib/mysql/cloud.lower-test
2020-02-12T07:47:33.947631Z 0 [Warning] Can't create test file /var/lib/mysql/cloud.lower-test
2020-02-12T07:47:33.948025Z 0 [ERROR] Could not open file '/var/log/mysqld.log' for error logging: Permission denied
2020-02-12T07:47:33.948066Z 0 [ERROR] Aborting
2020-02-12T07:47:33.948138Z 0 [Note] Binlog end
2020-02-12T07:47:33.948287Z 0 [Note] mysqld: Shutdown complete

mysqldump 检查:最后,我尝试使用上面的三个命令(即 mysqldump SHOW VARIABLES LIKE 'max_allowed_pa​​cket' )将“mysql”替换为“mysqldump”,但我被拒绝访问。作为替代方案,然后我成功登录到 mysqldump 以读取 max_allowed_pa​​cket (mysqldump --user userName --password databaseName),并且我在屏幕上滚动了很多垃圾,所以我无法获得这个值。

标签: phpmysqlpostmax-allowed-packet

解决方案


事实证明,这与 MySQL 没有直接关系。

致命错误:第 175 行 /home/client/public_html/phpfile.php 中允许的内存大小为 134217728 字节已用尽(尝试分配 32000179 字节)

这是一条 PHP 错误消息,它告诉您您的脚本已超出 128M内存限制

您可以在配置文件或脚本中增加限制

ini_set('memory_limit','256M');

您可以使用-1as value 完全禁用限制。

但是 - 您应该避免复制大量数据。

下面的案例很清楚:

$itemAttributes=$_POST['itemAttributes'];

您将 32M 的数据复制到一个新变量中。你的脚本现在至少有 64M。

带参数的execute()方法比较棘手,我不确定以下是否完全正确:你传递一个新数组作为参数

[$itemName,$itemAttributes]

这个数组首先需要在内存中创建,然后才能传递给execute(). 这再次消耗至少 32M 更多。然后由于内部实现(我不知道),每个数组元素都被传递给类似的东西bindValue(),这将再次复制所有数据。此时您的脚本已经达到 128M 的限制 (32*4)。

因此,您应该执行以下操作:

删除这些行:

$itemAttributes=$_POST['itemAttributes'];
$itemName=$_POST['itemName'];

准备声明:

$stmt = $conn->prepare("INSERT INTO $itemTable (`itemName`, `itemAttributes`) VALUES (?, ?)");

使用bindParam绑定参数:

$stmt->bindParam(1, $_POST['itemName'], PDO::PARAM_STR);
$stmt->bindParam(2, $_POST['itemAttributes'], PDO::PARAM_LOB);

bindParam()正在使用引用调用,您可以在描述中看到

公共 PDOStatement::bindParam ( 混合 $parameter , 混合 &$variable [, int $data_type = PDO::PARAM_STR [, int $length [, mixed $driver_options ]]] ) : bool

&in&$variable表示不会进行复制,而是传递对值的引用。

请注意,我通常不是通过引用调用的朋友,并且在不处理资源关键代码时避免使用它。execute([..])在大多数情况下都很好。

如果您想查看分配了多少内存,可以在脚本末尾的某处使用memory_get_peak_usage() 。


推荐阅读