1. 程式人生 > >【原創】PHP訪問MySQL查詢超時處理

【原創】PHP訪問MySQL查詢超時處理

               

PHP連線MySQL主要是使用Mysql提供的 libmysqlclient 的客戶端庫,同時也延伸出來 mysql 和  mysqli 兩套PHP的擴充套件,相對來說 mysqli 比 mysql 更好,更穩定。

目前兩個客戶端擴充套件庫連線超時可以設定選項來操作,比如mysqli:

<?php//建立物件$mysqli = mysqli_init();

//設定超時選項$mysqli->options(MYSQLI_OPT_CONNECT_TIMEOUT, 5);

//連線$mysqli->real_connect('localhost', 'my_user', 'my_password', 'world');

//如果超時或者其他連線失敗列印錯誤資訊if (mysqli_connect_errno()) {    printf("Connect failed: %s/n", mysqli_connect_error());    exit();}//成功輸出連線資訊printf ("Connection: %s/n.", $mysqli->host_info);

$mysqli->close();?>

這個是連線超時,但是有些時候我們需要查詢讀寫超時,比如說我們一個數據庫壓力很大,或者連線很多,那麼資料庫查詢就很緩慢,但是我希望某些不重要的資料,比如說文章點選數這種如果查詢超時了就不顯示,至少能夠保證主體頁面正確顯示,但是查遍PHP手冊沒有發現這個操作選項或者函式。

手冊裡只有這麼四個選項

跟蹤 mysqli 的擴充套件原始碼發現它底層呼叫的是 libmysqlclient 的 mysql_options:

php-5.2.8/ext/mysqli/mysqli_api.c

並且在mysqli的PHP擴充套件中就只匯出了幾個變數:

php-5.2.8/ext/mysqli/mysqli.c

大概看了一下 libmysqlclient 的程式碼,發現其實它自帶是有讀寫超時設定的:

mysql-5.1.30/sql-common/client.c

因為它自己定義了很多操作選項,只是php擴充套件裡沒有:

mysql-5.1.30/include/mysql.h

看看mysql中的讀寫超時是如何實現的:

mysql-5.1.30/sql-common/client.c

讀寫超時真正操作的地方,超時處理這裡重試了兩次,還是寫死了:

mysql-5.1.30/sql/net_serv.cc

現在基本得出了結論:

按照上面檢視程式碼來看,目前PHP針對MySQL查詢超時以下限制:

1. 超時設定單位為秒,最少配置1秒

2. 但mysql底層的read會重試兩次,所以實際會是 3 秒

重試兩次 + 自身一次 = 3倍超時時間。

那麼就是說最少超時時間是3秒,不會低於這個值,對於大部分應用來說可以接受,但是對於小部分應用需要優化。

現在我們來看看如果我們自己要設定超時,我們自己壓入 MYSQL_OPT_READ_TIMEOUT 也是可以達到讀寫超時效果的,寫一段程式碼來測試一下:

<?php//自己定義讀寫超時常量if (!defined('MYSQL_OPT_READ_TIMEOUT')) {        define('MYSQL_OPT_READ_TIMEOUT',  11);}if (!defined('MYSQL_OPT_WRITE_TIMEOUT')) {        define('MYSQL_OPT_WRITE_TIMEOUT', 12);}

//設定超時$mysqli = mysqli_init();$mysqli->options(MYSQL_OPT_READ_TIMEOUT, 3);$mysqli->options(MYSQL_OPT_WRITE_TIMEOUT, 1);

//連線資料庫$mysqli->real_connect("localhost", "root", "root", "test");if (mysqli_connect_errno()) {   printf("Connect failed: %s/n", mysqli_connect_error());   exit();}

//執行查詢 sleep 1秒不超時printf("Host information: %s/n", $mysqli->host_info);if (!($res=$mysqli->query('select sleep(1)'))) {    echo "query1 error: ". $mysqli->error ."/n";} else {    echo "Query1: query success/n";}

//執行查詢 sleep 9秒會超時if (!($res=$mysqli->query('select sleep(9)'))) {    echo "query2 error: ". $mysqli->error ."/n";} else {    echo "Query2: query success/n";}

$mysqli->close();echo "close mysql connection/n";?>

檢視上面程式碼的執行結果,驗證了上面的觀點,第一個查詢成功了,第二個查詢連線被斷開了:

如果需要修改這個秒級別的超時,比如改成毫秒級別的超時,只能兩個地方修改:

1.修改客戶端,比如 mysqli query 程式碼,加入定時器,超時則返回

2.修改 Mysql 中的vio程式碼,因為mysql的網路處理底層都是經過vio的操作

MySQL相關的vio程式碼:

poll 超時:

setsockopt 超時:

基本上到這裡就基本能夠解決PHP在針對MySQL讀寫查詢操作超時的處理了,希望對你有幫助。