PHP - Manual: 错误处理
2024-12-22
应用程序使用本插件,应该针对用户的 API 调用实现一些错误处理。并且由于插件 改变了连接控制,API 调用可能返回不可预期的错误。如果插件被用于连接控制中, 那么连接将不在代表一个独立的网络链接,他是一个连接池。那么一个错误编号和 错误消息将被设置在连接控制中,那么他可能被设置在任何一个实际的连接中。
如果使用默认的被动连接,那么连接再实际查询执行以前是不建立实际连接的。 这样一个执行语句的 API 调用会产生一个连接错误。下面的范例中,当尝试在 slave 中执行一个语句的时候将产生一个错误。连接错误的产生是因为在配置文件中 没有设定一个有效的 slave。
Example #1 Provoking a connection error
{ "myapp": { "master": { "master_0": { "host": "localhost", "socket": "\/tmp\/mysql.sock" } }, "slave": { "slave_0": { "host": "invalid_host_name", } }, "lazy_connections": 1 } }
明确的指定被动连接设定只是为了范例目的使用。
Example #2 在查询执行时产生连接错误
<?php
$mysqli = new mysqli("myapp", "username", "password", "database");
if (mysqli_connect_errno())
/* Of course, your error handling is nicer... */
die(sprintf("[%d] %s\n", mysqli_connect_errno(), mysqli_connect_error()));
/* 连接 1:在连接中绑定 SQL 用户定义变量,没有 SELECT 所以在 master 上运行 */
if (!$mysqli->query("SET @myrole='master'")) {
printf("[%d] %s\n", $mysqli->errno, $mysqli->error);
}
/* 连接 2:运行 SELECT 在 slave,产生一个连接错误 */
if (!($res = $mysqli->query("SELECT @myrole AS _role"))) {
printf("[%d] %s\n", $mysqli->errno, $mysqli->error);
} else {
$row = $res->fetch_assoc();
$res->close();
printf("@myrole = '%s'\n", $row['_role']);
}
$mysqli->close();
?>
以上例程的输出类似于:
PHP Warning: mysqli::query(): php_network_getaddresses: getaddrinfo failed: Name or service not known in %s on line %d PHP Warning: mysqli::query(): [2002] php_network_getaddresses: getaddrinfo failed: Name or service not known (trying to connect via tcp://invalid_host_name:3306) in %s on line %d [2002] php_network_getaddresses: getaddrinfo failed: Name or service not known
应用程序希望通过有效的错误处理控制这种连接错误。
处于使用的目的,应用程序应该希望控制这些错误,典型的错误内容 2002 (CR_CONNECTION_ERROR) - Can't connect to local MySQL server through socket '%s' (%d), 2003 (CR_CONN_HOST_ERROR) - Can't connect to MySQL server on '%s' (%d) 和 2005 (CR_UNKNOWN_HOST) - Unknown MySQL server host '%s' (%d)。 例如,应用程序可以判断这些错误编号,进而手动的执行某些错误处理。插件并不会自动的进行 这些错误处理,包括 master 错误处理,因为这些并不是透明的操作。
Example #3 产生一个连接错误
{ "myapp": { "master": { "master_0": { "host": "localhost" } }, "slave": { "slave_0": { "host": "invalid_host_name" }, "slave_1": { "host": "192.168.78.136" } }, "lazy_connections": 1, "filters": { "roundrobin": [ ] } } }
明确的指定被动连接只为了进行范例使用,包括使用默认的负载均衡策略 random once。
Example #4 非常基础的错误处理
<?php
$mysqli = new mysqli("myapp", "username", "password", "database");
if (mysqli_connect_errno())
/* Of course, your error handling is nicer... */
die(sprintf("[%d] %s\n", mysqli_connect_errno(), mysqli_connect_error()));
/* Connection 1, connection bound SQL user variable, no SELECT thus run on master */
if (!$mysqli->query("SET @myrole='master'")) {
printf("[%d] %s\n", $mysqli->errno, $mysqli->error);
}
/* 连接 2:第一个 Slave 执行 */
$res = $mysqli->query("SELECT VERSION() AS _version");
/* 强硬的进行错误处理 */
if (2002 == $mysqli->errno || 2003 == $mysqli->errno || 2004 == $mysqli->errno) {
/* 连接 3:第一个 slave 连接失败,尝试下一个 slave 连接 */
$res = $mysqli->query("SELECT VERSION() AS _version");
}
if (!$res) {
printf("ERROR, [%d] '%s'\n", $mysqli->errno, $mysqli->error);
} else {
/* 从连接 3 中获取错误信息,他并没有错误 */
printf("SUCCESS, [%d] '%s'\n", $mysqli->errno, $mysqli->error);
$row = $res->fetch_assoc();
$res->close();
printf("version = %s\n", $row['_version']);
}
$mysqli->close();
?>
以上例程的输出类似于:
[1045] Access denied for user 'username'@'localhost' (using password: YES) PHP Warning: mysqli::query(): php_network_getaddresses: getaddrinfo failed: Name or service not known in %s on line %d PHP Warning: mysqli::query(): [2002] php_network_getaddresses: getaddrinfo failed: Name or service not known (trying to connect via tcp://invalid_host_name:3306) in %s on line %d SUCCESS, [0] '' version = 5.6.2-m5-log
由于一些原因,连接控制并不可能很容易在所有网络连接中检查所有的错误。 例如,我们假设在连接池中有 3 个网络链接,一个连接是 master 连接,2个是 slave 链接。 应用程序通过 mysqli_select_db() API 调用改变当前操作数据库, 插件监控到这个函数,并且尝试更改当前的所有连接来统一他们的链接状态。如果 master 已经成功的更改了数据库,两个 slave 连接更改失败,那么在使用第一个 slave 连接的时候, 其中会包含一个连接错误。对于第二个 slave 链接也是一样的,那么在第一个 slave 上的 错误信息将被丢失。
这种情况下,可以通过检查 E_WARNING 类型的错误,或者检查 mysqlnd_ms debug and trace log。
官方地址:https://www.php.net/manual/en/mysqlnd-ms.errorhandling.php