错误处理

应用程序使用本插件,应该针对用户的 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

关注编程学问公众号