php封裝pdo實例以及pdo長連接的優缺點

一、前言

      最近需要寫腳本來實現崩潰日誌的入庫,不出所料又是脫離於框架的,那麼行吧,咱們只能自己封裝數據庫相關操作了。博主這裏選擇了封裝pdo操作數據庫相關。

二、爲什麼選擇pdo

      衆所周知的,php在早期的時候是帶有mysql擴展的,但是後來由於過於古老缺失了mysql的新特性,因此主鍵沒落。

      從php5開始,更建議大家使用mysqli擴展,這個是mysql擴展的增強版,是一個面向對象的MySQL接口,更容易使用。缺點是隻能操作mysql,不夠強大。

      還有就是pdo擴展了,這個是最豐富的的一個擴展,支持多種數據庫,重要的是,在安全上是比其他兩種擴展都要強的,通過使用prepared預處理更是有效的防止sql注入。因此,博主這裏選擇了封裝pdo相關的操作。

三、pdo的長連接

1、什麼是pdo的長連接

      長連接顧名思義就是一直保持連接,相對於平時的短連接,每次請求都會重新創建鏈接來說,長連接可以有效的減少創建的過程,可以更好的節省性能。

在操作上是在連接數據庫的時候,多加一個參數:

$pdo = new PDO($dsn, $username, $passwd, [PDO::ATTR_PERSISTENT => true]);

後面的PDO::ATTR_PERSISTENT => true 就是開啓長連接的方法。

2、長連接對nginx無效嗎

      博主在搜索長連接相關知識的時候,看到一篇文章,結論是長連接僅適用於apache,不適用於nginx,這是真的嗎?

參考博文地址:https://www.cnblogs.com/wpjamer/articles/7106389.html

      大致結論是:長連接更多的是針對於apache的,因爲apache維護一個進程池,開啓了apache mpm功能之後,apache會默認維持一個進程池,mysql長連接之後的連接,並沒有作爲socet連接關閉,而是作爲一個不釋放的東西,放進了進程池/線程池裏面去。

      而對於nginx來說,長連接是無效的,腳本執行結束則釋放資源?

3、php-fpm下的長連接測試

這裏前輩已經測試過了,咱們給出前輩的地址,大家有興趣的可以看看

參考博文地址:https://hacpai.com/article/1526490593632

結論:
      事實證明php-fpm是可以實現長連接的,只是如果該進程空閒的話,會造成資源浪費。

      php-fpm的配置文件可以考慮設置pm.max_requests = 1000,代表每一個子進程的最大請求服務數量,如果超過了這個值,該子進程會被自動重啓。

      比如max_requests這個參數,如果設置很大的話,那這個子進程要運行很多次纔會重啓,假如這個請求發生了錯誤或者內存泄漏,那麼這個值設置很大是不合適的。但如果請求沒有問題,這個值設置小的話就會頻繁的重啓,這樣也會碰到不少502的問題,所以要仁者見仁,智者見智的設置了,這裏初始化設置1000,如果測試沒有內存泄漏等問題,可以再大一些。

4、長連接對事務的影響

參考博文地址:https://www.zhihu.com/question/62603122

總結: 如果業務併發比較大且帶有事務,不建議使用長連接的方式。

5、總結

      博主在不斷的搜索中,發現長連接要發揮出最佳性能始終是避不開連接池這點的,而php恰恰又不能很好的實現連接池,這點確實是有點小遺憾。

      整體來說在php中是暫時無法配置和mysql的完美連接池的,在業務比較複雜的地方,還是謹慎試用長連接,每個連接都是1個線程,會造成大量的資源浪費。

      如果是某些業務需要持續的數據庫操作,比如提交日誌接口等,那麼是可以考慮打開長連接的,記得設置max_requests來定量關閉php-fpm連接,fpm關閉之後也會自動釋放mysql的連接。

      還有pm.max_spare_servers設置服務器空閒時最大php-fpm進程數量。

例如: pm.max_spare_servers = 25 如果空閒時,會檢查進程數,多於25個了,就會關閉幾個,達到25個的狀態。

      擅長swoole的同學,可以參考這篇文章:
基於swoole擴展實現真正的PHP數據庫連接池

四、pdo部分demo的封裝

      首先這部分博主是參考了一個網友的封裝,github地址如下:

https://github.com/nadirvishun/php-pdo-class

      這個網友基本的增刪改查都封裝好了,而且都有參數預處理,安全性還是可以的。不過既然作爲一個基準的類,還是缺少一些東西。

1、斷線重連機制

例如重連函數:

    /**
     * @params:重連函數,上限3次
     * @date:2020/3/18
     * @time:17:03
     */
    public function customConnect()
    {
        try {
            $this->pdo = new PDO($this->config['dsn'], $this->config['username'], $this->config['password'], $this->config['params']);
            $this->pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); //需要將錯誤處理模式變成異常模式
            return true;
        } catch (Exception $e) {
            if (stripos($e->getMessage(), 'MySQL server has gone away') !== false || stripos($e->getMessage(),' bytes failed with errno=10053') !==false) {
                $this->close();
                $this->tryNums++;
                if ($this->tryNums > 3) {
                    return false;
                }
                self::customConnect();
            } else {
                $this->throw_exception($e->getMessage());
                return false;
            }
        }
    }

2、轉化php warnings爲try…catch可捕獲的錯誤

      這步原因是長連接會頻繁的造成mysql gone away錯誤,而這個錯誤是phpwarnings級別錯誤,try..catch根本就捕獲不到,所以博主這裏自定義錯誤處理函數來處理。

      這部分是轉化phpwarnings錯誤爲try..catch可以捕獲的error錯誤,關於php的報錯機制以及錯誤處理這塊,咱們下篇再討論。

//自定義warnings處理函數
set_error_handler('customException');

//拿到warnngs錯誤之後,轉化爲error錯誤拋出,這樣就可以被try..catch捕獲
function customException( $error_no, $error_msg, $error_file, $error_line)
{
    throw new \Exception($error_msg,0,null);
    //throw new \Exception($error_msg);
}

3、析構方法回收資源

    /**
     * destruct 關閉數據庫連接
     */
    public function destruct()
    {
        $this->pdo = null;
    }

4、query的時候ping一下

  public function query($sql = null, $param = null)
    {
        //檢測連接是否活躍
        $this->pdo_ping();
        //判斷之前是否有結果集
        if (!empty($this->PDOStatement)) {
            $this->free();
        }
        xxxxxxxxxx
        }

5、下載地址

      這四步完善之後,這個pdo的類還是可以用的,大家需要的話可以去百度雲上下載。

鏈接: https://pan.baidu.com/s/1Siz_bKlhEIVNV99Y0zTzqw 提取碼: ebqx

最近這段時間挺頹廢的,不過疫情已經過去,春天已經到來,是時候奮鬥了少年,奧利給!

end

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