關於數據庫斷線重連的一點點思考

最近在寫數據庫鏈接池,一個不可逃避的問題就是數據庫斷線重連。 查了很多資料,因爲公司有很多項目用了 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版本有關。。。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章