1. 程式人生 > >C實現PHP的mysql資料庫連線池

C實現PHP的mysql資料庫連線池

一、導語

連線池在JAVA中應用的很廣泛,而在PHP中很少使用。 以Mysql為例,JAVA中使用連線池的原因之一是避免重複新建、釋放連線資源帶來的開銷。而在PHP中都是直連,因為這部分開銷對於C API而言效能上是沒有問題的。 那麼既然PHP直連已經沒有效能問題,那為何還要多次一舉開發mysql的資料庫連線池擴充套件呢?因為根本的目的是在於理解PHP的TS(Tthread Safe執行緒安全)與NTS(Not Thread Safe非執行緒安全)執行模式,而並非資料庫連線池這個功能。

二、原理

連線池的基本思想是在系統載入時,初始化預設數量的連線物件儲存在記憶體中,當有客戶端需要訪問資料庫時,根據場景選擇是分配、新建、等待、失敗返回連線物件。使用完畢之後,連線將被重新放置回連線池中等待下一個請求的再分配,而不是釋放記憶體。 連線池中連線的建立、釋放都由連線池自身來管理,同時可以通過設定初始化最小連線數、最大連線數、最大空閒時間等來配置連線池。 注:在此擴充套件中,提供了最小連線數(min_connection)、最大連線數(max_connection)的設定

三、實現思路

1.定義全域性陣列變數dbpools
dbpools中的元素型別為
struct _mysql_node{
     MYSQL *mysql;//連線資源控制代碼
     int is_used;//標記是否被佔用
     int result_id;//記錄my_mysql_query的查詢結果集
} mysql_node;
2.通過獲取配置檔案中設定的min_connection初始化dbpools
3.定義全域性變數db_pools_length(目前擁有連結數)、db_pools_use_length(目前被使用的連結數),通過這兩個值來確定分配資源的情景
注:正因為使用全域性變數實現連線池,通過修改全域性變數的狀態來選擇資源連線,決定了該擴充套件必須執行在共享全域性變數的ZTS(Zend Thread Safe)執行緒安全模式下。(例如IIS或Apache MPM Worker模式)
如果希望支援多程序,可以通過程序間通訊來設定全域性變數,實現執行緒池。 實現思路圖:

四、理解PHP執行緒與程序的工作模式

(一)多程序工作模式 PHP的多程序工作模式以Apache apxs舉例。 apache啟動時,會fork出N個子程序用來等待接受處理客戶端的請求。程序之間相互隔離,全域性變數也無法直接訪問(可以通過程序間通訊訪問)。這樣的好處是能夠保證PHP環境的長時間穩定, 即使有部分程序因記憶體洩漏而崩潰也不會影響其他程序。由於PHP相當於粘合劑,它實際相當於集合多個庫的API,例如集合了libcurl、libmemcache、libzip等,要保證所有的庫都正常執行是比較困難的。 那麼為了保證PHP的高可靠性,這種多程序的模式就是首選。


(二)多執行緒工作模式
PHP的多執行緒工作模式以IIS舉例。 這種模式下,只有一個程序在後臺執行著,所有請求都是通過這一個程序來完成。只是在處理每個請求時,會建立獨立的執行緒來處理。 正是因為使用多執行緒這種模式,可以直接訪問全域性變數得以方便的實現資料庫連線池。

六、使用此擴充套件前提條件與方法

1.widnwos下IIS Server或Apache多執行緒模式,php5.3.* 2.修改php.ini,新增 [my_mysql]
my_mysql.host = localhost
my_mysql.user = root
my_mysql.password = 
my_mysql.port = 3306
my_mysql.max_connection = 200 //最大連線數
my_mysql.min_connection = 100  //預設最小連線數 看到這裡的配置,能看出來這個資料庫連線池擴充套件沒有實現多資料來源的連線池。因為目的不在連線池本身,所以也沒有特地去寫多資料來源的功能。 3.修改php.ini,新增 extension=php_my_mysql.dll 4.重啟apache server 七、相關下載

擴充套件測試結果

測試配置: [my_mysql]
my_mysql.max_connection = 2 //最大連線數
my_mysql.min_connection = 1  //預設最小連線數 使用三個瀏覽器,執行下列測試指令碼:
<?php
/**
* 從資料庫連線池中取得一個連結資源
* 可能產生如下情景
* 1.如果有空閒連線則直接返回連結資源
* 2.如果沒有空閒連線,並且連線數沒有超過最大連線數,則擴充連線池並返回新建的連結資源
* 3.如果沒有空閒連線同時已經是最大連線數,則進入等待,超過1.5s仍沒有空閒資源則超時返回NULL.
*
* 失敗返回NULL
*/
$db = my_mysql_get_conn();

if($db === false){
     exit('dbpool is exhushed.');
}

/**
* 選擇資料庫
* @param resource $db
* @param string $db_name 資料庫名稱
*/
my_mysql_select_db($db, 'test');

/**
* ping資料庫
*/
my_mysql_ping($db);

/**
* 執行SQL語句,可以執行INSERT、SHOW、SELECT、UPDATE、DELETE等語句
* @param  resource $db
* @param string $sql SQL
*/
my_mysql_query($db, "INSERT INTO test VALUES(id, 'dbpool', 'test dbpool')");

// //獲取上一條INSERT語句返回的自增ID
$id = my_mysql_get_insert_id($db);
echo $id;

$result = my_mysql_query($db, "SELECT * FROM test");

/**
* 將查詢結果轉換為二維陣列
* @param resource $db
*/
$arr = my_mysql_fetch_assoc($result);

print_r($arr);

sleep(3);

var_dump($db);//sleep之後,必須輸出$db,否則會因為PHP的解析優化,sleep過程中已經將$db釋放,就沒有辦法測試連線被佔用的情況。

測試結果圖:
返回warning的,是由於連線池資源被佔用完,會進入等待。如果1.5s仍沒有等待到資源,則返回dbpool is exhushed。