mysql INSERT не работает, но ошибки не возникает: max_allowed_packet: настройки показывают противоречивые результаты
Я успешно получаю данные в учетную запись клиента сервера через _POST, но я не могу вставить данные в таблицу строк, содержащую типы longblob, когда данные строки превышают ~25 МБ. Я не вижу никаких ошибок, вызванных подготовленными операторами / файлом php, файл php закрывается изящно. Я проверяю, правильно ли настроен мой max_allowed_packet.
У меня нет корневых привилегий и доступа к серверу, я не вижу 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 не будет переопределен в другом месте и правильно настроен во всех местах?
Проверка настроек клиента: все эти три проверки дают мне max_allowed_packet 256 МБ:
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)
Проверка настроек сервера: как я могу проверить сервер max_allowed_packet на предмет GLOBAL и SESSION? Я пытаюсь заменить "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: наконец, я пытаюсь прочитать max_allowed_packet для mysqldump с помощью трех вышеперечисленных команд (т.е. mysqldump SHOW VARIABLES LIKE 'max_allowed_packet'), заменяя mysql на mysqldump, но мне отказано в доступе. В качестве альтернативы я затем успешно вхожу в mysqldump, чтобы прочитать max_allowed_packet (mysqldump --user userName --password databaseName), и я получаю много мусора, прокручивающего экран, поэтому я не могу получить это значение.
1 ответ
Как оказалось, это не имеет ничего общего с MySQL напрямую.
Неустранимая ошибка: разрешенный объем памяти 134217728 байт исчерпан (попытка выделить 32000179 байт) в /home/client/public_html/phpfile.php в строке 175
Это сообщение об ошибке PHP, которое сообщает вам, что ваш скрипт превысил ограничение памяти 128 МБ.
Вы можете увеличить лимит либо в файле конфигурации, либо в сценарии с помощью
ini_set('memory_limit','256M');
Ты можешь использовать -1
как значение, чтобы полностью отключить ограничение.
Однако вам следует избегать копирования больших объемов данных.
Ясно следующий случай:
$itemAttributes=$_POST['itemAttributes'];
Вы копируете 32M данных в новую переменную. И ваш скрипт сейчас как минимум 64M.
В execute()
метод с параметрами более сложен, и я не уверен, верно ли следующее: вы передаете новый массив в качестве параметра
[$itemName,$itemAttributes]
Этот массив сначала необходимо создать в памяти, прежде чем он будет передан в execute()
. Это опять же потребляет как минимум на 32 млн больше. Затем из-за внутренней реализации (которой я не знаю) каждый элемент массива передается во что-то вроде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()
использует вызов по ссылке, которую вы можете увидеть в описании
public PDOStatement::bindParam (смешанный параметр $, смешанный &$ переменная [, int $data_type = PDO::PARAM_STR [, int $length [, смешанный $driver_options ]]]): bool
&
в &$variable
указывает, что копирование не будет выполнено, но вместо этого будет передана ссылка на значение.
Обратите внимание, что я обычно не сторонник обращения по ссылке и избегаю этого, когда не имею дела с критически важным кодом.execute([..])
в большинстве случаев нормально.
Если вы хотите увидеть, сколько памяти было выделено, вы можете использовать memory_get_peak_usage() где-нибудь в конце вашего скрипта.