关于数据库断线重连的一点点思考

最近在写数据库链接池,一个不可逃避的问题就是数据库断线重连。 查了很多资料,因为公司有很多项目用了 TP5 于是也去看了它的源码。

tp5的实现其实很简单,配置了一些数据库连接相关的错误信息关键词(句),然后在执行语句时 catch 异常信息进行比对:

// 服务器断线标识字符
    protected $breakMatchStr = [
        'server has gone away',
        'no connection to the server',
        'Lost connection',
        'is dead or not enabled',
        'Error while sending',
        'decryption failed or bad record mac',
        'server closed the connection unexpectedly',
        'SSL connection has been closed unexpectedly',
        'Error writing data to the connection',
        'Resource deadlock avoided',
        'failed with errno',
    ];
catch (\PDOException $e) {
            if ($this->isBreak($e)) {
                return $this->close()->query($sql, $bind, $master, $pdo);
            }
            throw new PDOException($e, $this->config, $this->getLastsql());
        }
protected function isBreak($e): bool
    {
        if (!$this->config['break_reconnect']) {
            return false;
        }
        $error = $e->getMessage();
        foreach ($this->breakMatchStr as $msg) {
            if (false !== stripos($error, $msg)) {
                return true;
            }
        }
        return false;
    }

(噢 突然发现5.2已经开始使用 php7新特性了)

感觉用 errMessage 没有 errCode 靠谱吧,但是用 errCode 也很头疼啊,我要搜集各种数据库的连接相关的错误码,tp5自带的那些错误信息也只是 mysql 的吧,至少没看见sqlserver 的“TCP Provider: Error code 0x2746”,我的连接池是想支持多种数据库的。。。

正在头疼的时候,突然灵光一现:

从连接池取出db连接对象时,先执行一句类似“select 1”这样的非常简单、不会有语法错误、与业务无关(表无关、字段无关。。。) 的语句,如果报错则理论上证明即使不是连接问题 它也已经不能正常执行业务SQL了,再加一个重连次数限制,防止特殊情况下有可能发生的死循环。。。应该就完美了。。。

/**
     * 检查 db连接对象 是否可用, 主要针对断线重连
     * @param $dbKey
     * @return bool
     */
    static private function _check($dbKey)
    {
        try {
            self::$dbUsing[$dbKey]->check();
        } catch (\Exception $e) {
            return false;
        }
        return true;
    }
function check(){
        $this->prepare('select 1');
        return $this->execute();
    }

还有一种思路是做“心跳”检查,定时把连接池里的对象“请”出来“遛”一下,使其保持“活力”。。。但是这个和断线重连并不冲突,可以叠加使用,效果更好。。。


另:在测试中发现,mysql 好像可以自动重连具体表现为:在一个断开的 pdo连接对象执行第一句sql 时 catch 了异常并让代码继续执行,则后面的 sql 就可以执行成功。

我在网上没有查到这一行为相关资料,所以不确定它与 pdo 有关或是 mysql 的功能 又是否跟mysql版本有关。。。

猜你喜欢

转载自my.oschina.net/u/2399303/blog/1939668