php - mysql INSERT 失败但未抛出错误:max_allowed_packet:设置显示冲突结果
问题描述
我通过 _POST 成功地将数据接收到服务器客户端帐户,但是当行数据高于 ~25MB 时,我无法将数据插入到包含 longblob 类型的行表中。我看不到 php 准备好的语句/文件引发的任何错误,php 文件正常关闭。我正在检查我的 max_allowed_packet 是否配置正确。
我没有服务器 root 权限和访问权限,我看不到 my.cnf,我正在与我的主机交谈以确保客户端和服务器 max_allowed_packet都设置为 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_packet 不会在其他地方被覆盖并且在所有地方都正确设置?
客户端设置检查:所有这三个检查给我 256MB max_allowed_packet:
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_packet 但它显示为 NULL,这是什么意思?
mysql> select @max_allowed_packet;
+---------------------+
| @max_allowed_packet |
+---------------------+
| NULL |
+---------------------+
1 row in set (0.00 sec)
服务器设置检查:如何检查 GLOBAL 和 SESSION 的服务器“max_allowed_packet”?我尝试将上面的“mysql”替换为“mysqld”,但没有得到任何结果和警告,我无法与“max_allowed_packet”的大小相关:
[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_packet' )将“mysql”替换为“mysqldump”,但我被拒绝访问。作为替代方案,然后我成功登录到 mysqldump 以读取 max_allowed_packet (mysqldump --user userName --password databaseName),并且我在屏幕上滚动了很多垃圾,所以我无法获得这个值。
解决方案
事实证明,这与 MySQL 没有直接关系。
致命错误:第 175 行 /home/client/public_html/phpfile.php 中允许的内存大小为 134217728 字节已用尽(尝试分配 32000179 字节)
这是一条 PHP 错误消息,它告诉您您的脚本已超出 128M内存限制。
您可以在配置文件或脚本中增加限制
ini_set('memory_limit','256M');
您可以使用-1
as 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() 。
推荐阅读
- c# - 如何使用 nUnit、Selenium 计算 DOM 元素中的元素?
- java - SpringData JPA 本机查询提供 java.sql 数据而不是 LocalDate
- button - 在 1602 LCD 上滚动文本,同时聆听按钮按下
- bash - 如何从 Heroku 为单个 bash 命令设置环境变量,而不是为整个 shell 会话设置环境变量?
- python - 如何使用循环和命令输出的if条件
- python - 如何使用flask/python从sql表中获取
- swt - jface TreeViewer 的滚动锁定
- python - flask sqlalchemy 将数据库名称作为字符串传递
- electron - 如何在电子应用程序中包含模板组件的分布
- python-3.x - 在 Pandas 中查找目录中的总文件大小