PHP Conference Japan 2024

mysqli::poll

mysqli_poll

(PHP 5 >= 5.3.0, PHP 7, PHP 8)

mysqli::poll -- mysqli_poll轮询连接

描述

面向对象风格

public static mysqli::poll(
    ?array &$read,
    ?array &$error,
    array &$reject,
    int $seconds,
    int $microseconds = 0
): int|false

过程式风格

mysqli_poll(
    ?array &$read,
    ?array &$error,
    array &$reject,
    int $seconds,
    int $microseconds = 0
): int|false

轮询连接。此方法可用作静态方法。

注意:

仅在使用mysqlnd时可用。

参数

read

要检查可读取的未完成结果的连接列表。

error

发生错误的连接列表,例如查询失败或连接丢失。

reject

被拒绝的连接列表,因为没有运行异步查询,函数无法轮询其结果。

seconds

最大等待秒数,必须是非负数。

microseconds

最大等待微秒数,必须是非负数。

返回值

成功时返回就绪连接的数量,否则返回false

错误/异常

当没有传递readerror参数时,将抛出ValueError异常。

变更日志

版本 描述
8.3.0 现在,当没有传递readerror参数时,会抛出ValueError异常。

范例

示例 #1 一个mysqli_poll()示例

<?php
$link1
= mysqli_connect();
$link1->query("SELECT 'test'", MYSQLI_ASYNC);
$all_links = array($link1);
$processed = 0;
do {
$links = $errors = $reject = array();
foreach (
$all_links as $link) {
$links[] = $errors[] = $reject[] = $link;
}
if (!
mysqli_poll($links, $errors, $reject, 1)) {
continue;
}
foreach (
$links as $link) {
if (
$result = $link->reap_async_query()) {
print_r($result->fetch_row());
if (
is_object($result))
mysqli_free_result($result);
} else die(
sprintf("MySQLi Error: %s", mysqli_error($link)));
$processed++;
}
} while (
$processed < count($all_links));
?>

以上示例将输出

Array
(
    [0] => test
)

参见

添加备注

用户贡献的笔记 5 个笔记

l_sanczyk at hotmail dot com
10 年前
您可以使用以下代码来执行例如 10 个同时查询

$query = "SELECT `field1`, `field2` FROM `table` WHERE `field1`='something'";

$all_links = array();
for($i=0; $i<10; $i++) {
$link = mysqli_connect("your.mysql.server.here","your@user","pa$$w0rd",DataBase_Name");
$link->query($query, MYSQLI_ASYNC);
$all_links[] = $link;
}

$processed = 0;
do {
$links = $errors = $reject = array();
foreach ($all_links as $link) {
$links[] = $errors[] = $reject[] = $link;
}
if (!mysqli_poll($links, $errors, $reject, 1)) {
continue;
}
foreach ($links as $link) {
if ($result = $link->reap_async_query()) {
print_r($result->fetch_row());
if (is_object($result))
mysqli_free_result($result);
} else die(sprintf("MySQLi Error: %s", mysqli_error($link)));
$processed++;
}
} while ($processed < count($all_links));

注意:如果您收到“Warning: mysqli::query() expects parameter 2 to be long, string given”警告,则您的 mysqlnd 安装或配置存在问题。
shestero at meta dot ua
8 年前
有时不清楚连接“ready”是什么意思。它是指查询已完成,还是只是有一些记录可以读取?
是否可以使用异步(非阻塞)和非缓冲的 SELECT 查询?即同时使用 MYSQLI_ASYNC|MYSQLI_USE_RESULT

我想在我的循环中添加一些类似轮询的代码,该代码有四个情况选项
1. 轮询等待超时,但结果集没有准备好任何记录。
2. 一条或多条记录已准备好读取(但查询仍在运行)。
3. 查询已成功完成(已完成;没有更多记录)。
4. 错误。

这可能吗?

据我理解,如果目前没有准备好任何记录,则从非缓冲查询读取记录的操作是阻塞的,并且没有函数可以获取有多少记录已准备好?
marcin dot wanat at gmail dot com
1年前
值得注意的是,此文档中的示例会导致在您可以获取结果之前等待所有查询执行完毕。

5年前,来自 php.net 的 bishop 发布了一个解决方案,允许在每个查询执行后立即获取结果。由于某种原因,这从未合并到 php 手册中。

https://bugs.php.net/bug.php?id=70505

mysqli_poll 的文档建议在运行轮询后迭代链接。

foreach ($links as $link) {
if ($result = $link->reap_async_query()) {
print_r($result->fetch_row());
if (is_object($result))
mysqli_free_result($result);
} else die(sprintf("MySQLi Error: %s", mysqli_error($link)));
$processed++;
}

当您有多个运行时间的查询时,这不是一个好方法,因为 mysqli_reap_async_query() 会阻塞直到查询解决,这与异步轮询的本质相反。

一种尊重不同运行时间的多个查询的方法是对每个修改后的数组运行一个收割函数。

$count = mysqli_poll($read, $error, $reject, 1);
if (0 < $count) {
array_walk($read, 'reap');
array_walk($error, 'reap');
array_walk($reject, 'reap');
}

function reap($link) {
$result = mysqli_reap_async_query($link);
if (is_object($result)) {
print_r($result->fetch_assoc()));
mysqli_free_result($result);
} else if (false !== $result) {
print_r($link);
} else {
die(mysqli_error($link));
}
}

这也处理查询是 CRUD 并且 reap_async_query 的结果不是结果对象的情况。
ekalashnikov at gmail dot com
7年前
改进的轮询版本,用于检查慢速查询,
"KILL #ID" 如果 myqsli 链接的 ID 与终止它的 ID 相同,则不起作用,
因此您必须从 mysqli 断开连接,然后使用新链接重新连接以
终止 #ID。
<?php
// 慢速 SQL 查询
$SelectSql = 'SELECT * FROM SLOW_QUERY';
$link = mysqli_connect('localhost','user','pass','database');
mysqli_query($SelectSql, MYSQLI_ASYNC);
$thread_id = mysqli_thread_id($link);
// 忽略用户中断,以便我们可以终止查询
ignore_user_abort(true);
$MaxTime = 5; // 秒
$Overtime = false;
$StartTime = time();
do
{
// 轮询 MySQL
$links = $errors = $reject = array($link);
$poll = mysqli_poll($links, $errors, $reject, 0, 500000);
// 检查连接是否已中止以及查询是否已终止
if (connection_aborted()) {
$link_new = mysqli_connect('localhost','user','pass','database');
mysqli_kill($link_new, $thread_id);
$kill = mysqli_kill($link_new, $thread_id);
if (
$kill)
{
die();
}
}
$EndTime = time();
// 检查超时,如果检测到超时则终止
if ($EndTime - $StartTime > $MaxTime)
{
$link_new = mysqli_connect('localhost','user','pass','database');
mysqli_kill($link_new, $thread_id);
$Overtime = true;
echo
'Error: Query took over '.$Overtime.'.';
}
} while (!
$poll && $Overtime == false);
?>
ekalashnikov at gmail dot com
7年前
这是您可以使用轮询测试和终止慢速查询的方法。

<?php
// 慢速 SQL 查询
$SelectSql = 'SELECT * FROM SLOW_QUERY';
$link = mysqli_connect('localhost','user','pass','database');
mysqli_query($SelectSql, MYSQLI_ASYNC);
$thread_id = mysqli_thread_id($link);
// 忽略用户中断,以便我们可以终止查询
ignore_user_abort(true);
$MaxTime = 5; // 秒
$Overtime = false;
$StartTime = time();
do
{
// 轮询 MySQL
$links = $errors = $reject = array($link);
$poll = mysqli_poll($links, $errors, $reject, 0, 500000);
// 检查连接是否已中止以及查询是否已终止
if (connection_aborted() && mysqli_kill($link, $thread_id)) {
die();
}
$EndTime = time();
// 检查超时,如果检测到超时则终止
if ($EndTime - $StartTime > $MaxTime)
{
mysqli_kill($link, $thread_id);
$Overtime = true;
echo
'Error: Query took over '.$Overtime.'.';
}
} while (!
$poll && $Overtime == false);
?>
To Top