Когда вы запускаете длинный запрос из PHP, [как] я могу убить запрос, если пользователь нажимает кнопку остановки в своем браузере?
Учтите, что я не могу вызывать какие-либо другие функции PHP, потому что PHP блокируется во время ожидания MySQL.
Также я не могу делать больше запросов на сервер (через Ajax) из-за блокировки сеанса.
Таким образом, одним из решений может быть:
2 вещи, которые я не знаю, как это сделать:
Для тех, кто заинтересован, вот что я использовал:
<?php // Connection to query on $query_con = mysqli_connect($host, $user, $password, $name, $port); // Connection to kill on $kill_con = mysqli_connect($host, $user, $password, $name, $port); // Start the query $query_con->query($slow_query, MYSQLI_ASYNC); // Get the PID $thread_id = $query_con->thread_id; // Ignore user abort so we can kill the query ignore_user_abort(true); do { // Poll MySQL $links = $errors = $reject = array($mysqli->mysqli); $poll = mysqli_poll($links, $errors, $reject, 0, 500000); // Check if the connection is aborted and the query was killed if (connection_aborted() && mysqli_kill($kill_con, $thread_id)) { die(); } } while (!$poll); // Not aborted, so do stuff with the result $result = $link->reap_async_query(); if (is_object($result)) { // Select while ($row = $result->fetch_object()) { var_dump($row); } } else { // Insert/update/delete var_dump($result); }
Как только PHP замечает, что пользователь остановил запрос (обычно этого не произойдет, пока скрипт не попытается вывести что-то пользователю), ваш скрипт завершится. Перед закрытием PHP вызывает любые активированные вами функции выключения. Вы можете реализовать функцию выключения, которая убивает ваш запрос, и зарегистрировать его с помощью register_shutdown_function()
Другой способ, которым вы могли бы это сделать, – запустить ваш скрипт с ignore_user_abort()
и проверить, был ли пользователь прерван путем вызова connection_aborted()
периодически. Если пользователь прервал, убейте запрос и изящно выйдите из сценария.
Дополнительную информацию о подключении можно получить здесь .
Если время, затраченное на запрос, связано с mysql_unbuffered_query
большого набора данных, вы можете использовать mysql_unbuffered_query
. А затем в shutdown_function
вы можете освободить результат и отключить форму mysql.
И если вы используете PHP 5.3.x и имеете mysqlnd
вы можете, вероятно, использовать MYSQLI_ASYNC
в mysqli_query, а затем использовать mysqli_poll
для получения результата.
Первый вариант поможет только в случае времени, затрачиваемого на поиск набора данных. Но если mysql на самом деле занимает много времени в разборе и создании плана выполнения и загрузки таблиц в память, это не поможет. В этом случае вам нужен MYSQLI_ASYNC
который доступен только на PHP 5.3.x
С mysqlnd
.
Кроме того, если ваша основная проблема session locking
, посмотрите на это сообщение в документации PHP http://php.net/manual/en/ref.session.php#64525
Вы можете найти полезные советы.
я думаю, вы можете попробовать mysql KILL
http://dev.mysql.com/doc/refman/5.0/en/kill.html
если вы можете вызывать что-то по поводу прерывания пользователя, вы можете использовать KILL
чтобы убить ваше соединение или запрос mysql, извлекая его идентификатор процесса.
И как вы сказали в своем комментарии, что PHP блокируется до тех пор, пока mysql не вернется
поэтому вы можете получить помощь от javascript таким образом:
1.позволить пользователю прервать использование JS 2. вызвать функцию от пользователя abort 3. в этой функции вы можете убить предыдущий запрос, но здесь вам нужен идентификатор процесса предыдущего запроса, чтобы вы могли получить это с помощью трюка, который вы можете выбрать идентификатор процесса, когда вы запускаете свой первый длинный запрос и передаете его функции JS и используете его при убийстве вашего запроса.
Надеюсь, это поможет вам.
PHP, в большинстве случаев, не будет знать, что соединение было закрыто (поскольку пользователь прервался), пока он не попытается отправить что-то по сети, а затем получит SIGPIPE. Единственное, что вы можете сделать, это попытаться работать с тайм-аутами, прерывая длинные запросы или убивая их из другого процесса.