PDOExceptionが出た
SQLSTATE[HY000]: General error: 2006 MySQL server has gone away
- PHP側のエラーは
Error while sending QUERY packet.
- 場所は比較的大きなサイズのLOBを突っ込むクエリの
execute()
の場所 - でもPHPの
memory_limit
(=128MB)に収まる程度だし、max_execution_time
(=30秒)に収まる程度 - MySQLのログには何も出てない
調べたこと
-
wait_timeout
の値が小さい? -
設定もいじってないし、
mysql -uhoge -p -e "show variables like '%timeout%'"
してもデフォルトの28800
秒になっている。 -
execute()
の直前に$pdo->query("SELECT 1")
とか実行してみたら普通に実行できた。 -
max_allowed_packet
の値が小さい? -
設定を変更して大きくしてある。
mysql -uhoge -p -e "show variables like '%allowed%'"
しても設定通りになっている。 -
クエリの前に接続を閉じてる?
-
上でも書いたとおり直前に実行したクエリは通る。
-
LOBが大きいから?
-
小さなLOBにするとエラーが出ない
原因
**setAttribute(PDO::ATTR_EMULATE_PREPARES, true);
**としていたことっぽい???
エミュレーションをオフにしたら治った。
クエリをダンプしてみた
$pdo = new PDO();
$pdo->beginTransaction();
$pdo->query("SELECT 1");
$stmt = $pdo->prepare("INSERT INTO foo(file) values (?)");
$stmt->bindValue(1,LOB,PDO::PARAM_LOB);
$stmt->execute();
$pdo->commit();
- エミュレーションON、大きなLOB(25MB)
Connect hoge@localhost as anonymous on po
Query START TRANSACTION
Query SELECT 1
Prepare INSERT INTO foo (file) VALUES (?)
Execute INSERT INTO foo (file) VALUES (LOB)
エミュレーションONなのに静的プレースホルダのような動きをしている。
QuitもCOMMITもしていない。Connectが消えているので、本当にserver has gone away
なことがわかる。
- エミュレーションON、小さなLOB(1文字)
Connect hoge@localhost as anonymous on po
Query START TRANSACTION
Query SELECT 1
Query INSERT INTO foo (file) VALUES (LOB)
Query COMMIT
Quit
正常な動作
- エミュレーションOFF、大きなLOB(25MB)
Connect hoge@localhost as anonymous on po
Query START TRANSACTION
Prepare INSERT INTO foo (file) VALUES (?)
Prepare SELECT 1
Execute SELECT 1
Execute INSERT INTO foo (file) VALUES (LOB)
Query COMMIT
Quit
正常な動作
まとめると
PDO::ATTR_EMULATE_PREPARES
がTRUE
のときにLOBをinsertしようとするとconnectionが消える
そんなこと聞いたこともないし、調べても出てこないし、原因はこれ以外のところ……?でもfalseにしたら治ったし……謎
環境
- CentOS Linux release 7.4.1708 (Core)
- PHP 7.1.15
- mysql Ver 15.1 Distrib 10.2.13-MariaDB, for Linux (x86_64) using readline 5.1
結論
よくわからない