pcntl_fork и соединение с MySQL пропало

У меня есть цикл foreach, который разветвляется внутри него. После того, как процесс разветвляется, он обращается к базе данных. Я получаю ошибку:

SQLSTATE[HY000]: General error: 2006 MySQL server has gone away

Дело в том, что я подключаюсь к базе данных после того, как разветвился.

Мой вопрос: почему это происходит?

Если это произойдет, получаю ли я доступ к базе данных перед разветвлением? Будет ли ребенок наследовать соединения с БД?

(примечание: я могу опубликовать код, но он довольно большой, так как все в классах, что может вызвать у меня замешательство при доступе к БД. Еще одна вещь, которую вы должны знать, это то, что я использую ZF.)

4 ответа

Решение

(комментарий -> ответ на запрос автора)

Читая больше об этом, я вижу, что раздвоенные дети наследуют db-соединение своих родителей, и это известная проблема: http://php.net/manual/en/function.pcntl-fork.php

Это помогло мне: http://www.electrictoolbox.com/mysql-connection-php-fork/

Особенно mysql_connect($server, $username, $password, true);

Вы можете избежать закрытия соединения при выходе из разветвленного процесса, если убиваете разветвленный процесс с помощью SIGKILL.

<?php
$dbh = new PDO('pgsql:host=localhost', $username, $password);
$pid = pcntl_fork();
if($pid == 0){
        register_shutdown_function(function(){
                posix_kill(getmypid(), SIGKILL);
        });
        exit;
}
sleep(1);
$statement = $dbh->query('select 1');
var_dump($statement);

Причина такого поведения в том, что когда процесс PHP завершается, PHP отправляет серверу базы данных команду "Завершить соединение". Но сокет будет закрыт системой только тогда, когда все ссылки на сокет закрыты. Использование SIGKILL поможет нам избежать отправки команды "Завершить соединение" на сервер базы данных.

За исключением того, что это не проблема. Это способ, которым pcntl_fork был разработан. Любое расширение (как четко указано в документации), которое поддерживает свои собственные файловые дескрипторы, будет иметь поврежденные дескрипторы, потому что все дочерние элементы и родители используют одни и те же файловые дескрипторы.

Вам необходимо закрыть соединение MySQL с родительским процессом, а затем создать новое соединение для каждого дочернего процесса.

<?php
$dbh = new PDO('pgsql:host=localhost', $username, $password);
$pid = pcntl_fork();
if(!$pid){
        // make new connection
        $newConnection = new PDO('pgsql:host=localhost', $username, $password);
        // do something in the child process.
        exit;
}else{ 
        // parent node
        $dbh = null; // close PDO connection
}
Другие вопросы по тегам