1. 程式人生 > >關於資料庫斷線重連的一點點思考

關於資料庫斷線重連的一點點思考

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