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
結論
よくわからない