一次php腳本執行過程當中屢次實例化PDO的情景分析

情景分析

腳本代碼:php

<?php

try {
    $dbh1 = new PDO('mysql:host=localhost;dbname=test', 'root', 'root');
} catch (PDOException $e) {
    exit('鏈接數據庫失敗1');
} finally {
    echo "鏈接成功1\n";
}

try {
    $dbh2 = new PDO('mysql:host=localhost;dbname=test', 'root', 'root');
} catch (PDOException $e) {
    exit('鏈接數據庫失敗2');
} finally {
    echo "鏈接成功2\n";
}

try {
    $dbh3 = new PDO('mysql:host=localhost;dbname=test', 'root', 'root');
} catch (PDOException $e) {
    exit('鏈接數據庫失敗3');
} finally {
    echo "鏈接成功3\n";
}

echo "保持鏈接中...\n";
sleep(10);
echo "執行結束\n";

CLI執行:mysql

root@78ad0df34cef:/home/www/test# php index.php
鏈接成功1
鏈接成功2
鏈接成功3
保持鏈接中...
執行結束

在腳本sleep過程當中,咱們查看mysql的鏈接信息:web

mysql> show processlist;
+----+------+-----------+------+---------+------+----------+------------------+
| Id | User | Host      | db   | Command | Time | State    | Info             |
+----+------+-----------+------+---------+------+----------+------------------+
|  3 | root | localhost | NULL | Query   |    0 | starting | show processlist |
| 24 | root | localhost | test | Sleep   |    6 |          | NULL             |
| 25 | root | localhost | test | Sleep   |    6 |          | NULL             |
| 26 | root | localhost | test | Sleep   |    6 |          | NULL             |
+----+------+-----------+------+---------+------+----------+------------------+
4 rows in set (0.00 sec)

能夠看到一個腳本的執行產生了三個數據庫鏈接,可是若是將後面的實例化的pdo實例賦值給以前實例化的pdo實例,則新的鏈接會替換掉前一個鏈接,而不會產生新的鏈接。因此咱們在編程過程當中,應該避免屢次實例化pdo,而產生沒必要要的數據庫性能消耗。sql

解決方案

  1. 封裝一個單例模式的類,該類實例化的過程就是建立pdo鏈接的過程。咱們要創建數據庫鏈接時,不是手動實例化pdo,而是去獲取這個類的實例。
  2. 實例化pdo類時,設定 持久鏈接 參數:
<?php
$dbh = new PDO('mysql:host=localhost;dbname=test', $user, $pass, array(
    PDO::ATTR_PERSISTENT => true
));
?>

PHP官方文檔的引用:數據庫

不少 web 應用程序經過使用到數據庫服務的持久鏈接得到好處。 持久鏈接在腳本結束後不會被關閉,且被緩存,當另外一個使用相同憑證的腳本鏈接請求時被重用。持久鏈接緩存能夠避免每次腳本須要與數據庫回話時創建一個新鏈接的開銷,從而讓web 應用程序更快。

官方所說的腳本結束,在fpm模式下就是指一次客戶端請求的結束另外一個使用相同憑證的腳本也就能夠對應成另外一個使用相同數據庫鏈接憑證的客戶端請求。首先咱們要知道,這兩次客戶端的請求是根據fpm-workers的空閒狀況,被分配給某個worker去執行的,因此兩次請求被分配到同一個worker的可能性很低。接着,咱們闡明下面的情景。編程

開啓持久鏈接以後,數據庫鏈接是被緩存於fpm進程之中的。若是某個fpm-worker進程中已經緩存了持久鏈接,此時可能出現以下兩種狀況:緩存

  • 當腳本中再次執行帶 ATTR_PERSISTENT 參數的pdo鏈接時,會複用以前的鏈接,而不會產生新的鏈接。
  • 當腳本中再次執行不帶 ATTR_PERSISTENT 參數的pdo鏈接時,還會再次產生一個新的數據庫鏈接。
相關文章
相關標籤/搜索