轉(zhuǎn)載出處:http://blog.csdn.net/heiyeshuwu/article/details/5869813
PHP連接MySQL主要是使用Mysql提供的 libmysqlclient 的客戶端庫,同時(shí)也延伸出來 mysql 和 mysqli 兩套PHP的擴(kuò)展,相對來說 mysqli 比 mysql 更好,更穩(wěn)定。目前兩個(gè)客戶端擴(kuò)展庫連接超時(shí)可以設(shè)置選項(xiàng)來操作,比如mysqli:
<?php
//創(chuàng)建對象
$mysqli = mysqli_init();//設(shè)置超時(shí)選項(xiàng)
$mysqli->options(MYSQLI_OPT_CONNECT_TIMEOUT, 5);//連接
$mysqli->real_connect('localhost', 'my_user', 'my_password', 'world');//如果超時(shí)或者其他連接失敗打印錯(cuò)誤信息
if (mysqli_connect_errno()) {
printf("Connect failed: %s/n", mysqli_connect_error());
exit();
}
//成功輸出連接信息
printf ("Connection: %s/n.", $mysqli->host_info);$mysqli->close();
?>
這個(gè)是連接超時(shí),但是有些時(shí)候我們需要查詢讀寫超時(shí),比如說我們一個(gè)數(shù)據(jù)庫壓力很大,或者連接很多,那么數(shù)據(jù)庫查詢就很緩慢,但是我希望某些不重要的數(shù)據(jù),比如說文章點(diǎn)擊數(shù)這種如果查詢超時(shí)了就不顯示,至少能夠保證主體頁面正確顯示,但是查遍PHP手冊沒有發(fā)現(xiàn)這個(gè)操作選項(xiàng)或者函數(shù)。手冊里只有這么四個(gè)選項(xiàng):
跟蹤 mysqli 的擴(kuò)展源代碼發(fā)現(xiàn)它底層調(diào)用的是 libmysqlclient 的 mysql_options:
php-5.2.8/ext/mysqli/mysqli_api.c
并且在mysqli的PHP擴(kuò)展中就只導(dǎo)出了幾個(gè)變量:
php-5.2.8/ext/mysqli/mysqli.c
大概看了一下 libmysqlclient 的代碼,發(fā)現(xiàn)其實(shí)它自帶是有讀寫超時(shí)設(shè)置的:
mysql-5.1.30/sql-common/client.c
因?yàn)樗约憾x了很多操作選項(xiàng),只是php擴(kuò)展里沒有:
mysql-5.1.30/include/mysql.h
看看mysql中的讀寫超時(shí)是如何實(shí)現(xiàn)的:
mysql-5.1.30/sql-common/client.c
讀寫超時(shí)真正操作的地方,超時(shí)處理這里重試了兩次,還是寫死了:
mysql-5.1.30/sql/net_serv.cc
現(xiàn)在基本得出了結(jié)論:
按照上面查看代碼來看,目前PHP針對MySQL查詢超時(shí)以下限制: 1. 超時(shí)設(shè)置單位為秒,最少配置1秒 2. 但mysql底層的read會(huì)重試兩次,所以實(shí)際會(huì)是 3 秒 重試兩次 + 自身一次 = 3倍超時(shí)時(shí)間。 那么就是說最少超時(shí)時(shí)間是3秒,不會(huì)低于這個(gè)值,對于大部分應(yīng)用來說可以接受,但是對于小部分應(yīng)用需要優(yōu)化。
現(xiàn)在我們來看看如果我們自己要設(shè)置超時(shí),我們自己壓入 MYSQL_OPT_READ_TIMEOUT 也是可以達(dá)到讀寫超時(shí)效果的,寫一段代碼來測試一下:
<?php
//自己定義讀寫超時(shí)常量
if (!defined('MYSQL_OPT_READ_TIMEOUT')) {
define('MYSQL_OPT_READ_TIMEOUT', 11);
}
if (!defined('MYSQL_OPT_WRITE_TIMEOUT')) {
define('MYSQL_OPT_WRITE_TIMEOUT', 12);
}//設(shè)置超時(shí)
$mysqli = mysqli_init();
$mysqli->options(MYSQL_OPT_READ_TIMEOUT, 3);
$mysqli->options(MYSQL_OPT_WRITE_TIMEOUT, 1);//連接數(shù)據(jù)庫
$mysqli->real_connect("localhost", "root", "root", "test");
if (mysqli_connect_errno()) {
printf("Connect failed: %s/n", mysqli_connect_error());
exit();
}//執(zhí)行查詢 sleep 1秒不超時(shí)
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";
}//執(zhí)行查詢 sleep 9秒會(huì)超時(shí)
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";
?>
查看上面代碼的執(zhí)行結(jié)果,驗(yàn)證了上面的觀點(diǎn),第一個(gè)查詢成功了,第二個(gè)查詢連接被斷開了:
基本上到這里就基本能夠解決PHP在針對MySQL讀寫查詢操作超時(shí)的處理了,希望對你有幫助。
// #####################################################
// #####################################################
本人按照作者的方法編代碼,運(yùn)行時(shí)在$mysqli->options(MYSQL_OPT_READ_TIMEOUT, 3);這一步就返回false了,實(shí)際查詢時(shí)READ_TIMEOUT也沒有發(fā)揮作用。后來看php-5.3.8\php-5.3.8\ext\mysqli\mysqli_api.c源代碼時(shí)發(fā)現(xiàn)PHP_FUNCTION(mysqli_options)里有一行代碼:
expected_type = mysqli_options_get_option_zval_type(mysql_option);
這個(gè)函數(shù)的作用是判斷options值類型,其中有一段:
#ifdef MYSQL_OPT_READ_TIMEOUT
case MYSQL_OPT_READ_TIMEOUT:
case MYSQL_OPT_WRITE_TIMEOUT:
case MYSQL_OPT_GUESS_CONNECTION:
case MYSQL_OPT_USE_EMBEDDED_CONNECTION:
case MYSQL_OPT_USE_REMOTE_CONNECTION:
case MYSQL_SECURE_AUTH:
#endif /* MySQL 4.1.1 */
.........
return IS_LONG;
.........
default:
return IS_NULL;
貌似由于沒有定義MYSQL_OPT_READ_TIMEOUT這個(gè)宏,所以options等于MYSQL_OPT_READ_TIMEOUT時(shí)被歸到IS_NULL的返回結(jié)果中了,此時(shí)PHP_FUNCTION(mysqli_options)會(huì)執(zhí)行如下結(jié)果:
switch (expected_type) {
case IS_STRING:
ret = mysql_options(mysql->mysql, mysql_option, Z_STRVAL_PP(mysql_value));
break;
case IS_LONG:
l_value = Z_LVAL_PP(mysql_value);
ret = mysql_options(mysql->mysql, mysql_option, (char *)&l_value);
break;
default:
ret = 1;
break;
}
也就是說,不會(huì)執(zhí)行mysql_options()方法,而是直接返回false。
簡單的說,就是修改mysqli和mysqlnd下的一些代碼,使MYSQL_OPT_READ_TIMEOUT和 WHEN_SUPPORTED_BY_MYSQLI兩個(gè)宏包含的代碼被編譯,詳細(xì)的方法見我的博客:
http://hi.baidu.com/zhoujin1012/blog/item/f17fd3dcd9ef0e3310df9b74.html