程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 數據庫知識 >> MYSQL數據庫 >> 關於MYSQL數據庫 >> Mysql入門系列:Perl DBI基礎(2)

Mysql入門系列:Perl DBI基礎(2)

編輯:關於MYSQL數據庫
如果使用fetchrow_hashref( ),請記住下列警告:

  如果性能很重要,則fetchrow_hashref( ) 並不是最好的選擇,因為它沒有fetchrow_array( ) 或fetchrow_arrayref( ) 的效率高。

  作為散列鍵值使用的列名具有與SELECT 語句中寫出時相同的字符。在MySQL中,列名不區分大小寫,所以此查詢也是這樣,不管以大寫字母還是小寫字母給出列名,查詢結果都是一樣的。但是Perl 散列索引名是區分大小寫的,這可能會帶來一些問題。為了避免潛在的大小寫不匹配問題,可通過傳遞NAME_lc 或NAME_uc 屬性,告知fetchrow_hashref( ) 強迫列名為大寫或小寫:

  

  散列對每個唯一的列名含有一個元素。如果正在執行從多個具有重疊名稱的表中返回列的連接,則不能訪問所有的列值。例如,如果發布下面的查詢, fetchrow_hashref( )將返回只有一個元素的散列:

  SELECT a.name FROM a,b WHERE a.name=b.name

  2. 確定查詢返回的行數

  如何知道SELECT 或類似於SELECT 的查詢返回的行數?一種方法是,當提取它們時,計算這些行的數量。實際上,這是知道SELECT 查詢返回多少行的唯一方便的方法。使用MySQL驅動程序,可以在調用execute( ) 後利用語句句柄調用rows( ) 方法,但是這對其他數據庫引擎並不方便。而且即使就MySQL來說,如果已經設置了MySQL_use_result 屬性,rows( ) 也不能返回正確的結果,直到提取了所有行(有關的詳細信息,請參閱附錄G)。所以只能如提取行一樣對它們進行計數。

  3. 提取單行的結果

  如果結果集只含單個行,則不需要運行循環來獲得結果。假設要編寫得出歷史同盟成員當前數量的腳本count _ member s。完成查詢的代碼如下所示:

  

  SELECT 語句只返回一行,所以不需要循環;我們只調用fetchrow_array( ) 一次。另外,因為我們只選擇一列,所以甚至不需要將返回值分配給數組。當在標量環境中(單個值而不是所期望的一列)調用fetchrow_array( ) 時,它返回這個行的第一列,如果沒有更多的有效行,則返回un d e f。

  另一種期望最多有一個記錄的查詢是一個含有LIMIT 1來約束返回的行數的查詢。其一般的用法是返回特定列含有最大或最小值的行。例如,下面的查詢給出最近出生的總統姓名和出生日期:

  

  必須無提取循環的其他類型的查詢利用MAX( ) 或MIN( ) 來選擇單個值。但是在所有這些情況下,獲得單個行結果的一種更容易的方法就是使用數據庫句柄方法selectrow_array( ),它結合了prepare( )、execute( ) 並在單個調用中提取行。它返回一個數組(而不是一個引用),如果出現錯誤,則返回一個空數組。前一例子可利用selectrow_array( ) 編寫如下:

  

  

  4. 處理完整的結果集

  在使用提取循環時, DBI 不提供在結果集中隨意查找的方法,或以任何次序而不是以循環返回的次序來處理行。同樣,提取行以後,如果沒有保存,前一行會丟失。這種做法並不一定合適以下情況:

  以非連續的次序處理行。考慮一種情況,想以歷史同盟的president 表中列出的美國總統為主體,進行一些測驗。如果希望每次測驗時都以不同的次序提出問題,則可以從president 表中選擇所有行。然後,可能以任意的次序提取行來改變與所問問題有關的總統的次序。要想任意地提取一行,就必須同時訪問所有的行。

  只使用返回行的子集,對其進行隨機選擇。例如,當問及總統出生地時,要想出現多個選擇的問題,則可以隨便地提取一行來選擇總統(正確的答案),然後再從取來干擾的選擇中提取若干其他行。

  即使確實以連續的次序去處理,也想緊緊抓住整個結果集。如果想經過這些行進行多個傳遞,這可能是必需的。例如,在統計計算中,可能先浏覽一遍結果集,來估計數據的一些通用數字屬性,然後再次檢查這些行,來實現更加明確的分析。

  可以用幾個不同的方式作為一個整體訪問結果集。可以完成這個常見的提取循環,並在提取它時保存每一行,可以使用一次返回整個結果集的方法。無論哪種方法都以在結果集中包括一行一行的矩陣作為結束,和選擇的列一樣多。可以以任何次序任意多次地處理矩陣的

  元素。下面的討論說明這兩種方法。

  使用提取循環來捕獲結果集的一種方法是使用fetchrow_array( ) 並保存對這些行引用的數組。除了保存所有的行,然後顯示矩陣舉例說明了如何確定矩陣中的行數和列數,及如何訪問矩陣的個別成員以外,下面的代碼和dump_members 中提取和顯示的循環作用是一樣的。

  

  

  在確定矩陣的維數時,必須首先確定行數,因為無論這個矩陣是否為空,都可能計算列數。如果$rows 為0,則這個矩陣為空,並且$cols 也為0。否則,列數可能作為行數組中的元素數量來計算,用語法@{$matrix[$i]} 來整體訪問行$ i。

  在前述的樣例中, 我們提取每一行, 然後保存對它的引用。可以設想調用fetchrow_arrayref( ) 而不是直接地檢索行引用可能更有效率:

  

  它不能正常工作,因為fetchrow_arrayref( ) 重新使用了引用指向的數組。結果矩陣是一個引用的數組,數組中的每個元素都指向相同行—最後檢索的行。因此,如果想一次提取一行,則要使用fetchrow_array( ) 而不是fetchrow_arrayref( )。

  另一個選擇是使用提取循環,可以使用返回整個結果集的DBI 方法中的一個。例如,fetchall_arrayref( ) 返回對引用數組的引用,數組的每個元素都指向結果集中某行。這非常簡單,但很有效,這個返回值是對矩陣的引用。要想使用fetchall_arrayref( ),則調用prepare( )和execute( ),然後如下檢索結果:

  

  如果結果集為空,則fetchall_arrayref( ) 返回一個對空數組的引用。如果出現錯誤,則結果為un d e f,所以如果沒有啟用R a i s e E r r o r,則在開始使用它以前,要確保檢查返回值。

  行數和列數由矩陣是否為空來確定。如果想作為一個數組訪問這個矩陣的整個行$ i,應該使用語法@ { $ m a t r i x _ r e f - > [ $ i ] }。

  使用fetchall_arrayref( ) 來檢索結果集當然比編寫一個提取行的循環要更簡單一些,盡管訪問數組元素的語法是一個小技巧。一個與fetchall_arrayref( ) 方法相類似,但卻做了更多工作的方法是selectall_arrayref( )。這個方法為您完成了整個prepare( )、execute( )、提取循環、finish( ) 序列。為了使用selectall_arrayref( ),應該利用數據庫句柄直接將查詢傳遞給它:

  

  5. 檢查NULL 值

  從數據庫中檢索數據時,可能需要區分值為NULL 、為0 或者為空字符串的列。因為DBI 返回NULL 列值作為un d e f,所以這種區分是容易的。然而,必須確保使用正確的測試。如果試用下面的代碼段,則它所有三次顯示都為“ f a l s e !”:

  

  而且,對於這兩個測試,這段代碼都顯示“ f a l s e !”:

  

  下面這段代碼效果相同:

  

  要想區分NULL 列值和非NULL 列值,則使用defined( )。知道了沒有出現NULL 值之後,使用適當的測試可以在其他類型值之間加以區分。例如:

  

  以適當的次序完成這些測試是很重要的,因為如果$col_val 為空字符串,則第二個和第三個比較就都為真。如果顛倒比較的次序,則會錯誤地將空字符串標識為0。

  引用問題

  迄今為止,我們已經利用引用字符串以最基本的方式構造了查詢。在引用的字符串含有引用值時,會在Perl 詞匯一級產生問題。在插入或者選擇含有引號、反斜槓或二進制數據的值時,在SQL 中也可能出問題。如果指定一個查詢作為Perl 引用的字符串,則必須避免在查詢字符串本身中出現引用字符:

  

  Perl 和MySQL都允許用單引號或雙引號引用字符串,所以混合使用引用字符有時可以避免這種無法引用引用字符自身的情況:

  

  然而,在Perl 中,這兩種類型的引號並不等價。只有在雙引號內部才解釋為變量引用。因此,當想通過在查詢字符串中嵌入變量引用來構造查詢時,單引號並不是非常有用的。例如,如果$var 的值為14,則下面的兩個字符串並不等價:

  

  兩個字符串的解釋如下所示;顯然,第一個字符串與希望傳遞給MySQL服務器的內容更為相像:

  

  用雙引號來引用字符串的另一個選擇是使用QQ{} 結構,它告訴Perl 在‘q q {’和‘}’之間的每個字符都要看作為雙引號括起的字符串(兩個q 表示“雙引號”)。例如,下列兩行是等價的:

  

  使用qq{} 時,構造查詢不用過多考慮引號的問題,因為可以在這個查詢字符串內自由地使用引號(單引號或雙引號),而不用避開它們。此外,還解釋了變量引用。QQ{} 的這兩種特性可用下面的INSERT 語句來說明:

  

  不一定使用‘ {’和‘ }’作為qq 的分隔符。其他格式,如qq( ) 和q q / /,也可以使用,只要封閉的分隔符不出現在字符串內即可。我喜歡用q q { },因為‘ {’不像‘)’或‘/’會出現在查詢的文本內,並且在查詢字符串的結尾也可能有問題。例如,‘)’出現在所顯示的INSERT 語句的內部,所以QQ( ) 對於引用查詢字符串來說不是一個有用的結構。

  QQ{} 結構能跨行,如果想讓查詢字符串在Perl 代碼中醒目,這很有用:

  

  如果希望將查詢格式分為多個行,從而使它的可讀性更強,這樣也很有用。例如,dump_members 腳本中的SELECT 語句如下:

  

  用q q { }編寫如下:

  

  

  雙引號字符串也可以跨行。但是,對於編寫多行的字符串,我更喜歡用q q { }。我發現當在一行中看到不匹配的引號時,我就自然地去想,“這會是語法錯誤嗎?”,然後,我就會浪費時間去尋找相匹配的引號。

  QQ{} 結構在Perl 詞匯級注意了引用的問題,因此可將引號容易地放到字符串內,而不會使Perl 搞混它們。然而,還必須考慮SQL 級的語法。考慮向member 表中插入一條記錄:

  

  do( ) 發送給MySQL的字符串如下所示:

  

  這是不合法的SQL 語句,因為在單引號字符串內出現了單引號。在第6章中,我們遇到過類似的引用問題。在那裡,我們使用MySQL_escape_string( ) 來處理這個問題。DBI 提供了一個類似的機制—在一條語句中,對想按字面使用的每個引用值,都調用quote( ) 方法,並使用它的返回值。

  前面的例子可編寫如下:

  

  現在,do( ) 發送給MySQL的字符串如下所示,具有出現在引用字符串內的可能對服務器轉義的引號:

  

  請注意,在查詢字符串中引用$last 和$first 時,不要增加括起來的引號; quote( ) 方法支持它們。如果增加了引號,則查詢將出現過多的引號,如下面的例子所示:

  

  這些語句產生下面的輸出:

  

  占位符和參數約束

  在前面各節中,我們通過把要插入或選擇的值作為選擇標准,直接放在查詢字符串中構造了查詢。不一定非要這樣做。DBI允許在查詢字符串內部放置一些稱為占位符的特殊標記符,然後,在執行該查詢時,將這些值代替那些標識符來使用。這樣做的主要原因是提高性能,特別是在循環中反復執行某個查詢的時候。

  為了說明占位符如何工作,舉例說明。假設學校新學期剛開始,打算清理學分薄的student 表,然後利用包含在文件中的一列學生姓名將其初始化,使其包含新學生。不用占位符,可以如下這樣刪除現有表的內容,並裝入新的姓名:

  

  這樣做效率很低,因為INSERT 查詢的基本格式每次都是相同的,並且在整個循環中,do( ) 每次都調用prepare( ) 和execute( )。在進入這個循環以前,只調用一次prepare( ) 來設置INSERT 語句,並且在這個循環內部只調用execute( ),這樣做效率更高一些。只調用一次prepare( ),可避免其他多次調用。DBI 允許我們這樣做:

  

  請注意這個INSERT 查詢中的‘ ?’就是一個占位符。調用execute( ) 時,將查詢發送給服務器,傳遞這個值來代替占位符。一般來說,如果發現在循環內部調用了do( ),應該在循環前調用prepare( ),並在這個循環內部調用execute( ) 更好一些。

  有關占位符的一些注意事項:

  在查詢字符串內,不要在引號中封裝占位符字符。如果這樣做,不能識別為占位符。

  不要使用quote( ) 方法來指定占位符的值,否則將在插入的值中得到額外的引號。

  在查詢字符串中可以有一個以上的占位符,但是要確保占位符的標記符與傳遞給execute( ) 的值一樣多。

  每個占位符都必須指定一個單獨的值,而不是一列值。例如,不能運行這樣的語句:

  

  為了將NULL 指定為占位符,應該使用un d e f。

  不要對關鍵字使用占位符。這樣會出問題,因為占位符的值是由quote( ) 自動處理的。

  關鍵字將被放在引號括起來的查詢中,因此,這個查詢會由於語法錯誤而失敗。

  除了在循環中提高效率以外,對於某些數據庫引擎,可以從占位符的使用中獲得其他的性能好處。某些引擎高速緩存了准備好的查詢,以及為有效地運行這個查詢所生成的計劃。也就是說,如果以後這個服務器收到同樣的查詢,則它可以再次使用相應的計劃而不用生成。查詢高速緩存特別有助於復雜的SELECT 語句,因為可能需要花費時間生成較好的執行計劃。占位符提供了一個在高速緩存中尋找查詢的好機會,因為它們使查詢比直接在查詢字符串中嵌入指定的列值來構造查詢更通用。對於MySQL,在這種方式下,占位符並不提高性能,因為沒有高速緩存查詢。然而,可能仍想使用占位符編寫自己的查詢;如果偶然將DBI 腳本傳遞給支持查詢高速緩存的引擎,則這個腳本比沒有占位符時運行效率更高。

  在查詢運行時,允許在查詢字符串中用占位符代替這些值。換句話說,可以參數化這個查詢的“輸入”。在提取行而不必將值賦給變量時,DBI 也提供一個稱為參數約束的輸出操作,允許通過檢索自動進入這些變量的列值使“輸出”參數化。

  假設有一個查詢,檢索member 表中的成員姓名。可以告訴DBI 將選定列的值賦給Perl變量。在提取行時,變量利用相應的列值自動進行更新。下面是一個例子,說明如何將這些列約束到變量上,然後在提取循環中訪問它們:

  

  bind_col( ) 的每個調用都應該指定一個列號和一個希望與該列相聯的變量的引用。列號從1開始。bind_col( ) 應該在execute( ) 之後調用。

  還有一種選擇,就是單獨調用bind_col( ),可以在bind_columns( ) 的單個調用中傳遞全部變量引用:

  

  指定連接參數

  建立服務器的連接的最直接的方法為,調用connect( ) 方法時指定所有連接參數:

  

  如果遺漏連接參數,則DBI 做下面的事情:

  如果未定義數據源或未定義空字符串,則使用DBI_DSN 環境變量。如果未定義用戶名和口令,則使用DBI_USER 和DBI _ PASS 環境變量(但如果它們為空字符串則不使用)。在Windows 下,如果未定義用戶名,則使用user 變量。

  如果遺漏了主機名,其缺省值為localhost。

  如果將用戶名指定為undef 或空字符串,則其缺省為UNIX 的登錄名稱。在Windows 下,用戶名缺省為ODBC。

  如果將口令指定為undef 或空字符串,則不傳送口令。

  通過將某些選項添加到字符串的初始部分,每個都在分號前面,可以在數據源中指定這些選項。例如,可以使用MySQL_read_default_file 選項來指定一個選項文件的路徑名:

  

  當執行這個腳本時,它將從這個文件中讀取連接參數。假設/ u/ paul /.my.cnf 含有下面的內容:

  

  然後connect( ) 調用試圖連接到p i t - v i per-snake-net 上的MySQL服務器,並且用口令secret 及用戶名paul 連接。如果想允許具有正確地設置選項文件的任何人使用您的腳本,則像這樣指定數據源:

  

  $ENV{HOME} 含有用戶運行這個腳本的主目錄的路徑名,所以這個腳本使用的主機名、用戶名和口令將會從每個用戶自己的選項文件中抽取出來。以這種方式編寫腳本,不必在這個腳本中逐字地嵌入連接參數。

  還可以使用MySQL_read_default_group 選項,來指定一個選項文件組。這自動地導致讀取用戶的.my.cnf 文件,並且除了[clIEnt] 組以外,還允許讀取一個指定的選項組。例如,如果在DBI 腳本中具有指定的選項,則可以將它們列在[dbi] 組中,然後以如下方式使用數據源值:

  

  mysql_read_default_file 和mysql_read_default_group 需要MySQL3.22.10 或更新的版本,以及DBD::mysql1.21.06 或更新的版本。有關指定的數據源字符串的選項的詳細信息,請參閱附錄G。有關MySQL選項文件格式的詳細信息,請參閱附錄E。

  使用選項文件並不防礙在connect( ) 調用中指定連接參數(例如,如果想這個腳本作為特殊的用戶來連接)。在connect( ) 調用中指定的任何明確的主機名、用戶名和口令值都將覆蓋在選項文件中找到的連接參數。例如,想要腳本從命令行中分析- - host、--user 和--passWord 選項,並使用那些值,如果給定,則優先於在選項文件中發現的任何內容。這是有用的,因為它是標准的MySQL客戶機操作的方式。DBI 腳本將因此符合它的行為。

  對於在本章中我們開發的保留在命令行中的腳本,我將使用一些標准的連接設置代碼及卸載代碼。我只在這裡說明它一次,以便我們可以將精力集中在每個腳本的主體上,我們編寫如下代碼:

  

  

  這個代碼初始化DBI,在命令行中查找連接參數,然後使用命令行中的或者在用戶運行這個腳本的- /.my.cnf 文件中所找到的參數,連接到MySQL服務器。如果在主目錄中設置.my.cnf 文件,則當運行這個腳本時,不一定要輸入任何連接參數(請記住,設置這種方式,以便沒有其他人讀取這個文件。有關的指導請參閱附錄E)。

  我們腳本的最後部分也類似於從腳本到腳本;它簡單地終止這個連接並退出:

  $dhb->disconnect();

  exit (0);

  當我們讀到Web 程序設計的部分,即7 . 4節“在Web 應用程序中使用DBI”時,將修改一些這個連接設置代碼,但是基本的思想是類似的。

  調試

  當想調試有故障的DBI 腳本時,通常使用兩項技術,即單獨使用一個或一前一後地配合使用。首先,在腳本的整個過程中編寫顯示語句。它允許將自己調試的輸出設計為想要的方式,但必須手工地增加語句。其次,可以使用DBI 的內建跟蹤能力。這更加通用,但也更加

  系統,而且它在打開以後,則會自動地出現。DBI 跟蹤也說明一些除此以外就無法獲得的有關驅動程序的操作信息。

  1. 使用顯示語句調試

  在MySQL郵件清單中,常見問題之一是:“有一個查詢,當我在MySQL中執行它時運行得很好,但是它不能在我的DBI 腳本中工作,怎麼回事?”尋找發布不同查詢的DBI 腳本和這個發問者所期望的一樣是很平常的。如果在執行它之前顯示查詢,則可能會驚異地看到真

  正發送到這個服務器上的內容。假設將一個查詢鍵入到MySQL中(沒有終止的分號)

  

  然後,在DBI 腳本中試著做相同的事情:

  

  盡管它是同樣的查詢,但它不能工作。不是嗎?試著顯示:

  print "$query "

  結果如下:

  INSERT member (last_name,first_name,expiration)

  VALUES(Brown,Warcia,2002-6-3)

  從這個輸出中,可以看到是您忘記了VALUES( ) 列表中這些列值前後的引號。指定查詢的正確方法如下:

  

  或者,可以使用占位符指定查詢,並傳遞這些值,直接插入到do( ) 方法中:

  

  不幸的是,當做這些的時候,使用顯示語句不能看到完整查詢的樣子,因為直到調用d o ( )才能估計占位符的值。當使用占位符時,跟蹤可能對調試方法更有幫助。

  2. 使用跟蹤調試

  當試圖查出腳本不能正確工作的原因時,可以告知DBI 來生成跟蹤(調試)信息。跟蹤級別范圍從0(關閉)到9(最多信息)。一般來說,跟蹤級別1和2 是最有用的。級別2 跟蹤說明正在執行的查詢文本(包括占位符替換的結果)、調用quote( ) 的結果等等。這可能對捕獲問題有極大的幫助。

  使用trace( ) 方法,可以從獨立的腳本內部控制跟蹤,或者可以設置DBI_TRACE 環境變量來影響所運行的所有DBI 腳本的跟蹤。

  要想使用trace( ) 調用,則傳遞一個跟蹤級別參數,並可以有選擇地再傳遞一個文件名。如果沒有指定文件名,則所有的跟蹤輸出到STDERR 中;否則,它就轉到這個命名的文件中。一些樣例如下:

  

  當調用DBI->trace( ) 時,跟蹤所有的DBI 操作。一個更精細的方法是,可以用獨立的處理級別啟用跟蹤。當沒想好腳本中問題的位置,並對在那點出現的每件事的跟蹤輸出不想插手時,這是有幫助的。例如,如果特定的SELECT 查詢有問題,則可以跟蹤與這個查詢相關的語句句柄:

  

  如果對任何trace( ) 調用指定一個文件名參數,則無論對DBI 作為整體還是單獨的句柄,所有的跟蹤輸出都要到那個文件中。

  要想對運行的所有DBI 腳本全部都打開跟蹤,則從命令解釋程序中設置DBI_TRACE 環境變量。它的語法取決於使用的命令解釋程序:

  

  value 的模式和所有命令解釋程序的模式一樣:數字n表示在級別n打開跟蹤到S T D E R R中;文件名打開級別2 跟蹤到這個命名的文件,或n=file_name 打開級別n跟蹤到這個命名的文件中。下面的樣例使用了csh 語法:

  

  如果打開跟蹤到命令解釋程序中的文件,則確保一旦解決了這個問題,就將它關閉。將調試輸出增加到這個跟蹤文件中,而不用重寫它,所以如果不小心,則這個文件可能變得非常大。極其不好的想法是在命令解釋程序的啟動文件(如.cshrc、.lonin 或. p r o f i l e)中定義DBI _ T R A C E!在UNIX 下,可以使用下面兩個命令( csh 語法)之一關閉跟蹤:

  % setenv DBI_TRACE 0

  % unsetenv DBI_TRACE

  對於s h、ksh 或b a s h,這樣做:

  $ DBI_TRACE=0

  $export DBI_TRACE

  在Windows 操作系統中,可以使用下面兩個命令之一關閉跟蹤:

  c:>unset DBI_TRACE

  c:>set DBI_TRACE=0

  使用結果集元數據

  可以使用DBI 來獲得訪問結果集元數據——也就是有關由查詢選擇行的描述信息。訪問與結果集生成的查詢所相關的語句句柄的屬性來獲得這個信息。提供這些屬性中有一些是作為可用於橫跨所有數據庫驅動程序的標准DBI 屬性(如N U M _ O F _ F I E L D S,結果集中列的數量)。另外一些是MySQL特定的,由DBD::mysql所提供的DBI 的MySQL驅動程序。這些屬性,如mysql_max_length 告知了每列值的最大寬度,不能用於其他數據庫引擎。要想使用任何MySQL特定的屬性,都必須冒著使腳本不可移植到其他數據庫的危險。另一方面,它們可以使它更容易地獲得想要的信息。

  必須在適當時候請求元數據。一般來說,直到調用prepare( ) 和execute( ) 之後,結果集屬性才能用於SELECT 語句。除此之外,在調用finish( ) 之後,屬性可能變為無效。

  讓我們來看看如何使用MySQL的一個元數據屬性mysql_ m a x _ l e n g t h,與保留查詢列名的DBI 級別的NAME 屬性一起使用。我們可以將這些屬性提供的信息合並起來,編寫一個腳本b o x _ o ut,它以交互模式運行MySQL客戶機程序時獲得的相同邊框風格,從SELECT 查詢產生輸出。box_out 的主體如下(可以用任何其他的語句替換SELECT 語句;編寫輸出的例程獨立於特定的查詢):

  

  

  用execute( ) 將這個查詢初始化之後,我們獲得了所需的元數據。$sth->{NAME} 和$ s t h ->{MySQL_max_length} 給出了列名和每列值的最大寬度。為了在這個查詢中為列命名,每個屬性值都引用了一個數組,這個數組含有結果集每列中的一個值。

  剩余的計算非常類似於在第6章中開發的客戶機程序5中所使用的那些內容。例如,為避免偏離輸出,如果列的名比該列中任何數據值都寬,則我們要向上調整列的寬度值。

  輸出函數print_dashes( ) 和print_row( ) 代碼編寫如下,它們也類似於客戶機程序5中相應的代碼:

  

  box_out 的輸出如下:

  

  我們的下一個腳本使用了列元數據來產生不同格式的輸出。這個腳本s h o w _ member,允許快速浏覽歷史同盟成員項目,而不用輸入任何查詢。給出成員的姓,它就這樣顯示所選擇的項目:

  

  

  使用成員資格號碼,或者使用與若干姓相匹配的模式也可以調用s h o w _ member s。下面的命令說明成員號碼為2 3的項目,和以字母“C”開始的姓的成員項:

   show_member 腳本的主體如下所示。它使用了NAME 屬性來確定輸出的每行所使用的標號和NUM_OF_FIELDS 屬性,找出這個結果集含有的列數:

  

  

  無論區域是什麼, show_member 的目的都是說明一個項目的全部內容。通過使用SELECT * 來檢索所有的列和NAME 屬性來看看它們是什麼,即使從member 表中增加或刪除列,這個腳本也會工作而不用做修改。

  如果不檢索任何行就想知道一個表含有哪些列,則可以發布下面這條查詢:

  SELECT * FROM tbl_name WHERE 1=0

  以正常方式調用prepare( ) 和execute( ) 之後,可以從@{$sth->{NAME}} 中得到列名。然而,請注意,盡管使用“空”查詢的這個小竅門可以在MySQL下運行,但是它不可移植,而且並不是對所有的數據庫引擎都可以工作的。

  有關DBI 和DBD::mysql所提供屬性的詳細信息,請參見附錄G。它完全可以使您確定是想通過避免MySQL特定的屬性而為可移植性花費努力,還是在可移植性的開銷方面利用它們。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved