Убить запрос MySQL на прерывание пользователя

Когда вы запускаете длинный запрос из PHP, [как] я могу убить запрос, если пользователь нажимает кнопку остановки в своем браузере?

Учтите, что я не могу вызывать какие-либо другие функции PHP, потому что PHP блокируется во время ожидания MySQL.

Также я не могу делать больше запросов на сервер (через Ajax) из-за блокировки сеанса.

Таким образом, одним из решений может быть:

  • игнорировать пользовательский прерывание
  • запустите длинный запрос в фоновом режиме и проверите PHP каждые 100 мс, если он закончит
  • получить pid из запроса
  • если пользователь прерывает, убить pid
  • иначе верните результат, когда закончите

2 вещи, которые я не знаю, как это сделать:

  • запустить неблокирующий (фоновый) запрос
  • получить pid запроса

Для тех, кто заинтересован, вот что я использовал:

 <?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. Единственное, что вы можете сделать, это попытаться работать с тайм-аутами, прерывая длинные запросы или убивая их из другого процесса.