| |初探|欄位型態|運算元與函數|PHP 的 MySQL Functions|進階| | |
|---|---|
| MySQL 簡介 |
|
|
存取 MySQL | |
透過網頁存取資料庫內容的程式,多半要遵循以下幾個步驟來進行:
| |
建立資料庫連線 | |
| 我們將存取資料庫的過程,想像成一艘貨輪要進港載貨。首先,港務局(MySQL)會對我們進行身分驗證,以確定是否為貨物的擁有者。在通過身分驗證之後,我們將會得到一張「識別證」。 | |
| 一般而言,港務局會開放 3306 號港口(port)供我們上下貨物,因此我們不必多費唇舌,可以直接駛入其中;否則,我們還要將貨輪駛向特定的港口停放。 | |
|
$link = mysql_connect(HOSTNAME, USERNAME, PASSWORD); $link = mysql_connect(HOSTNAME:PORT, USERNAME, PASSWORD); | |
| 上面這行敘述在對 MySQL 表明存取者的身分。其中的 HOSTNAME 是「主機名稱」,若 Web server 與 MySQL 同在一部機器上的話,可以寫成「localhost」,否則請寫資料庫主機的名稱或 IP。USERNAME 與 PASSWORD 所指的就是要存取 MySQL 的帳號密碼了。 | |
| 一般的情況下,MySQL 會透過 3306 port 運作。若系統使用這項預設值的話,我們可以不用再加指定;否則請額外加入 PORT 參數來說明,如:「localhost:9000」。 | |
| 透過 mysql_connect( ) 的運作,MySQL 可以確認資料存取者的身分。成功的話,將回傳一個「link identifier」;否則傳回 FALSE。 | |
選定欲存取的資料庫 | |
| 取得通行許可之後,接著進入貨物區。這裡可能會有許多間貨品倉庫(資料庫),我們還要向管理員出示「識別證」,並從中挑選一間倉庫。 | |
|
mysql_select_db(DBNAME); mysql_select_db(DBNAME, Identifier); | |
| 上面的 DBNAME 指的是「資料庫名稱」,當面對單一資料庫時,Identifier 可以省略不寫。 | |
| 由於存取每個資料庫都需要一個個別的 link identifier,所以若我們想同時存取兩個資料庫時,必須建立兩個 link identifier ,並在 mysql_select_db( ) 裡指明哪一個 link identifier 將對應到哪一個資料庫。 | |
執行查詢動作 | |
| 此時,無論是要將貨物搬上船,或是將船上的貨品存放到倉庫中,請將工作清單(QueryString)拿出來,然後就可以開工了。 | |
|
$result = mysql_query(QueryString); $result = mysql_query(QueryString, Identifier); $result = mysql_db_query(DBNAME, QueryString, Identifier); | |
| QueryString 即我們對資料庫的查詢動作,它可能是一段資料查詢的敘述,也可能是新增、修改或刪除等異動資料的要求。當 $result 為 FALSE 時,表示這個存取動作是失敗的;否則,它將會是一個編號(ID)。在「取出查詢結果」的步驟,我們得靠它來識別這次的查詢結果。 | |
| 在使用 mysql_query( ) 時,Identifier 是可以省略不寫的。若我們不加以指定的話,系統會自動選用最近一次被使用的 link identifier。 | |
| 如果我們先前「選定欲存取的資料庫」這個步驟略過的話,現在可以改用 mysql_db_query( ) 來進行資料查詢的動作。也就是說,mysql_db_query( ) 的功能等同於 mysql_select_db( ) 加上 mysql_query( )。 | |
取出查詢結果 | |
| 取得貨物以後,拆開來看吧!裡頭分裝成一箱一箱的,我們可以算算有多少箱,也可以再把箱子拆開,取出裡面的貨品來。 | |
| 在上個步驟中,若我們執行的是查詢動作的話,MySQL 會將結果包裝成一個 result set,並傳回它的編號(ID),接下來要讀取資料時,都少不了它。 | |
| $number_of_rows = mysql_num_rows($result); | |
| 藉由 mysql_num_rows( ) 函數,我們可以得知這個 result set 裡頭有多少個資料列(row)。 | |
| 最後,再透過迴圈的運作,將 result set 裡的每個資料列一一讀出來。由於每個資料列可能含有多個欄位,所以 $data 將會是一個陣列;要一一顯示個別欄位內容的話,我們可以用 $data[0]、$data[1]、$data[2]、...... 的方式。 | |
|
for ( $i=0; $i<$number_of_rows; $i++ ) { $data = mysql_fetch_row($result); echo $data[0]; ...... } | |
| 要不然,使用以下這種方式也行:將各個欄位的值存入相對應的變數中。 | |
|
for ( $i=0; $i<$number_of_rows; $i++ ) { list($value1, $value2, $value3, ......) = mysql_fetch_row($result); echo $value1; ...... } | |
中斷資料庫連線 | |
| 任務達成,向港務局 say good bye 吧! | |
| mysql_close(Identifier); | |
| mysql_close( ) 可以用來關閉一個由 mysql_connect( ) 所建立的資料庫連結,但是這個動作不是必要的。因為當一支程式執行結束之後,資料庫連結會被自動中斷。 | |
經驗談
在建立資料庫連線時,除了上述的 mysql_connect( ) 以外,您也可以使用 mysql_pconnect( ) 來建立一個持續性的連線(persistent connection)。 用 mysql_connect( ) 建立的連線,用完即丟,乾淨俐落。不過,因為在建立資料庫連線時,需要耗費一些時間與系統資源;若使用「持續連線」的話,同一部 web server 再向 MySQL server 請求連線時,可以直接使用先前用完閒置的連線,而不必重建。所以使用 mysql_pconnect( ) 來建立連線,可以節省時間,同時也能降低伺服器的負擔。 兩者相較之下,mysql_pconnect( ) 顯然好得多,以後我們都使用它就好了。一般而言,這樣的說法是對的,坊間的相關書籍幾乎都支持這個論點;但我覺得它不完全正確,也就是說:在某些場合,mysql_pconnect( ) 是不適用的。
使用 1 部 web server 與 1 部 MySQL server(兩者可能同在一部主機上),而 web server 固定只對 MySQL server 上的某一個資料庫進行存取動作。 因為每次存取資料庫時,都是由 web 那邊使用同一帳號對 MySQL 上的同一資料庫作業,若我們將 MySQL 與 web server 的「同時連線數」都調整為 200,就好像 MySQL 這邊一直有 200 位「服務生」,隨時等著接待來自 web 的 200 位「顧客」似的。而且「顧客」離開之後,「服務生」也不下場休息,時時都站在門口等著接待下一個「顧客」。 在這種情況下,您只要注意將 MySQL 的「同時連線數」調得比 web server 的高或相等,就會發現使用 mysql_pconnect( ) 是個不錯的選擇。
使用 1 部 web server 與 1 部 MySQL server(兩者可能同在一部主機上),而 web server 會對 MySQL server 上的兩個資料庫進行存取動作。 從 web server 那邊提出資料存取需求時,有時是針對第 1 個資料庫(DB1),有時則是針對第 2 個資料庫(DB2)。若我們也將 MySQL 與 web server 的「同時連線數」都調整為 200,這樣一來,就好像 MySQL 這邊有 200 位「服務生」,但同時經營兩個「吧台」(DB1 與 DB2),而「顧客」可能多達 200 位。 一開始,DB1 這個「吧台」比較熱門,MySQL 派了 150 位「服務生」上場接待;同樣地,當「顧客」離開之後,這 150 位「服務生」仍守著 DB1 而不下場休息。後來,DB2 那邊也熱鬧起來了,「顧客」越來越多,MySQL 得加派「服務生」上場,有幾個能派?答案是 50 個! 為什麼「服務生」的人力調配會捉襟見肘?那是因為 web 那邊使用了 mysql_pconnect( ) 來建立連線。「服務生」一開始被指定到哪個「吧台」工作,就會持續在那邊停留,絕不「轉台」。 請注意,當使用持續性的連線時,每個已建立的連線只為來自同一部 web server、使用同一組帳號,且存取同一資料庫的使用者服務。 如此一來,假設每部 web server 的「同時連線數」都是 200,而且同時使用 2 部 web server 會怎麼樣呢?從 web1 來了 50 個「顧客」,先是到 DB1 走一趟,接著再到 DB2 晃一圈,這樣需要多少「服務生」接待他們?100 個(web1->DB1: 50 web1->DB2: 50)!又從 web2 來了 50 個「顧客」,也做了同樣的動作(web2->DB1: 50 web2->DB2: 50)。在此之後,還有「服務生」是閒著的嗎?後續若從 web1 或 web2 同時湧入多於 50 位「顧客」時,誰來應付他們? 倘若您使用的是像 Apache 這類的 multi-process web server(一個 parent process 協調一組 children processes 運作),某個 children process 建立的「持續連線」,是不能分享給其它 children process 來使用的(「服務生」只對先前接待過的「顧客」服務)。在這樣的情況下,將會使得 MySQL 上閒置的 process 越積越多(很多「服務生」站在門口等著「老顧客」上門,而不理會「新顧客」)。 mysql_pconnect( ) 一定是最佳選擇嗎?我想未必盡然。 說明: 「同時連線數」是有上限的,當所有連線都被佔用時,後續的連線要求就會被拒絕。「同時連線數」能調整到多高,這與伺服器本身的效能是息息相關的,因為調得愈高,所消耗的系統資源也就愈多。 | |
|
| |
| |初探|欄位型態|運算元與函數|PHP 的 MySQL Functions|進階| | |


建立資料庫連線
經驗談