亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁(yè) > 編程 > Perl > 正文

Perl DBI 基礎(chǔ)

2024-07-21 02:13:11
字體:
來(lái)源:轉(zhuǎn)載
供稿:網(wǎng)友
注冊(cè)會(huì)員,創(chuàng)建你的web開(kāi)發(fā)資料庫(kù),   本節(jié)提供dbi 的背景信息—在編寫(xiě)自己的腳本和支持其他人編寫(xiě)的腳本時(shí),需要這些信息。如果已經(jīng)熟悉dbi,則可以略過(guò)這節(jié),直接跳到7 . 3節(jié)“運(yùn)行dbi”。

dbi 數(shù)據(jù)類(lèi)型

    從某些方面來(lái)說(shuō),使用perl dbi api 類(lèi)似于使用第6章介紹的c 客戶(hù)機(jī)庫(kù)。在使用c 客戶(hù)機(jī)庫(kù)時(shí),主要依靠指向結(jié)構(gòu)或數(shù)組的指針來(lái)調(diào)用函數(shù)和訪問(wèn)與mysql相關(guān)的數(shù)據(jù)。在使用dbi api 時(shí),除了函數(shù)稱(chēng)為方法,指針?lè)Q為引用外,也調(diào)用函數(shù)和使用指向結(jié)構(gòu)的指針。
指針變量稱(chēng)為句柄,句柄指向的峁鉤莆韻蟆?br>     dbi 使用若干種句柄。它們往往通過(guò)表7-1所示的慣用名稱(chēng)在dbi 文件中引用。而慣用的非句柄變量的名稱(chēng)如表7 - 2所示。實(shí)際上,在本章中,我們并不使用每個(gè)變量名,但是,在閱讀其他人編寫(xiě)的dbi 腳本時(shí),了解它們是有用的。
表7-1慣用的perl dbi 句柄變量名

名稱(chēng)說(shuō)明
$dbh數(shù)據(jù)庫(kù)對(duì)象的句柄
$sth語(yǔ)句(查詢(xún))對(duì)象的句柄
$fh打開(kāi)文件的句柄
$h“通用”句柄;其意義取決于上下文

表7-2 慣用的perl dbi 非句柄變量的名稱(chēng)

名稱(chēng)說(shuō)明
$rc從返回真或假的操作中返回的代碼
$rv從返回整數(shù)的操作中返回的值
$rows從返回行數(shù)的操作中返回的值
@ary查詢(xún)返回的表示一行值的數(shù)組(列表)


一個(gè)簡(jiǎn)單的dbi 腳本

    讓我們從一個(gè)簡(jiǎn)單腳本d um p _ member s開(kāi)始,它舉例說(shuō)明了dbi 程序設(shè)計(jì)中若干標(biāo)準(zhǔn)概念,如與mysql服務(wù)器的連接和斷開(kāi)、檢索數(shù)據(jù)等。此腳本產(chǎn)生的結(jié)果為以制表符分隔形式列出的歷史同盟成員。這個(gè)格式本身并不讓人感興趣:在這里,了解如何使用dbi 比產(chǎn)生漂亮的輸出更為重要。
    dump_members 如下:


    要想自己試驗(yàn)這個(gè)腳本,可以下載它(請(qǐng)參閱符錄a),或使用文本編輯器創(chuàng)建它,然后使之可執(zhí)行,以便能運(yùn)行。當(dāng)然,可能至少需要更改一些連接參數(shù)(主機(jī)名、數(shù)據(jù)庫(kù)名、用戶(hù)名和口令)。本章中的其他dbi 腳本也是這樣。在參數(shù)缺省時(shí),本章下載腳本的權(quán)限設(shè)置為只允許讀。如果您將自己的mysql用戶(hù)名和口令放在它們之中,我建議將它們保留為這種方式,以便其他人不能讀取這些值。以后,在7 . 2 . 8節(jié)“指定連接參數(shù)”中,我們將看到如何從選項(xiàng)文件中獲得這些參數(shù),而不是將它們直接放在腳本中。
    現(xiàn)在,讓我們逐行看完這個(gè)腳本。第一行是標(biāo)準(zhǔn)行,指出哪里可以找到perl 的指示器:
    #! /usr/bin/perl
    在本章將要討論的腳本中,每個(gè)腳本都包含這行;以后不再說(shuō)明。此腳本中至少應(yīng)該含有一個(gè)簡(jiǎn)短的目的說(shuō)明,這是一個(gè)好主意,所以下一行是一個(gè)注釋?zhuān)o閱讀此腳本的人提供一個(gè)關(guān)于它做什么的線索:
    # dump_members.dump historical league's membership list
    從‘#’字符到行尾部的文本為注釋。有必要做一些練習(xí),就是在整個(gè)腳本中編寫(xiě)一些注釋來(lái)解釋它們?nèi)绾喂ぷ鳌?br>    接下來(lái)是兩個(gè)use 行:
    use dbi;
    use strict;
    use dbi 告知perl 解釋程序它需要引入dbi 模塊。如果沒(méi)有這一行,試圖在腳本中做與dbi 相關(guān)的任何事,都將出現(xiàn)錯(cuò)誤。不需要指出想要哪個(gè)dbd 級(jí)別的模塊。在連接數(shù)據(jù)庫(kù)時(shí),dbi 會(huì)激活相應(yīng)的模塊。
    use strict 告知perl,在使用它們之前需要聲明變量。如果沒(méi)有use strict 行,也可以編寫(xiě)腳本,但是,它有助于發(fā)現(xiàn)錯(cuò)誤,所以建議始終要包括這行。例如,置為嚴(yán)格模式時(shí),如果聲明變量$ my _ v a r,但是之后錯(cuò)誤地用$mv_var 來(lái)訪問(wèn),則在運(yùn)行這個(gè)腳本時(shí),將獲得下面的消息:
    global symbol "$mv_var" requires explicit package name at line n
    這個(gè)消息會(huì)使您想,“怎么了?$ m v _ v a r?我從未使用過(guò)這種名稱(chēng)的變量!”,然后,找到腳本中的第n行,看是什么問(wèn)題,并改正它。如果不用嚴(yán)格模式, perl 不會(huì)給出$ m v _ v a r;將只是簡(jiǎn)單地按具有un d e f(未定義的)值的該名稱(chēng)創(chuàng)建一個(gè)新的變量,并毫無(wú)動(dòng)靜地使用它,然后,您會(huì)莫名其妙腳本為什么不工作。
    因?yàn)槲覀冊(cè)趪?yán)格模式下操作,所以我們將定義腳本使用的變量:

    現(xiàn)在我們準(zhǔn)備連接數(shù)據(jù)庫(kù):

    connect( ) 調(diào)用作為dbi->connect( ) 來(lái)調(diào)用,因?yàn)樗莇bi 類(lèi)的方法。不必真正知道它是什么意思;它只是一個(gè)使人頭痛的面向?qū)ο蟮男性挘ㄈ绻拇_想知道,那么它意味著connect( ) 是“屬于”dbi 的一個(gè)函數(shù))。connect( ) 有若干參數(shù):
    數(shù)據(jù)源。(經(jīng)常調(diào)用的數(shù)據(jù)源名稱(chēng),或d s n。)數(shù)據(jù)源格式由要使用的特定dbd 模塊需求來(lái)確定。對(duì)于mysql驅(qū)動(dòng)程序,允許的格式如下:
    "dbi:mysql:db_name"
    "dbi:mysql:db_name:host_name"
    對(duì)于第一種格式,主機(jī)名缺省為localhost(實(shí)際上有其他允許的數(shù)據(jù)源格式,我們將在后面7 . 2 . 8節(jié)“指定連接參數(shù)”中討論)?!癲bi”大寫(xiě)沒(méi)關(guān)系,但是“ mysql”必須小寫(xiě)。
    用戶(hù)名和口令。
    表示額外連接屬性的可選參數(shù)。這個(gè)參數(shù)控制dbi 的錯(cuò)誤處理行為,我們指定的看起來(lái)有點(diǎn)奇怪的構(gòu)造啟用了raiseerror 屬性。這導(dǎo)致dbi 檢查與數(shù)據(jù)庫(kù)相關(guān)的錯(cuò)誤,并顯示消息,而且只要它檢測(cè)到錯(cuò)誤就退出(這就是為什么在dump_members 腳本中的任何地方都沒(méi)有看到錯(cuò)誤檢查代碼的原因; dbi 將它全部處理了)。7 . 2 . 3節(jié)“處理錯(cuò)誤”包括了對(duì)錯(cuò)誤響應(yīng)的可選方法。
    如果connect( ) 調(diào)用成功,則它返回?cái)?shù)據(jù)庫(kù)句柄,我們分配給$dbh(如果connect( ) 失敗,通常返回un d e f。然而,因?yàn)槲覀冊(cè)谀_本中啟用了r a i s e e r r o r,所以connect( )不返回;但是,dbi 將顯示一條錯(cuò)誤消息,并且在出現(xiàn)錯(cuò)誤時(shí)退出)。
    連接到數(shù)據(jù)庫(kù)后, dump_members 發(fā)布一條select 語(yǔ)句查詢(xún)來(lái)檢索全體成員列表,然后,執(zhí)行一個(gè)循環(huán)來(lái)處理返回的每一行。這些行構(gòu)成了結(jié)果集。
    為了完成s e l e c t語(yǔ)句,首先需要準(zhǔn)備,然后再運(yùn)行它:
    # issue query
    $sth=$dbh->prepare("select last_name,first_name,suffix,email,"
         "street,city,state,zip,phone from member order by last_name");
    $sth->execute();
    利用數(shù)據(jù)庫(kù)句柄調(diào)用prepare( );在執(zhí)行前,它將sql 語(yǔ)句傳遞給預(yù)處理的驅(qū)動(dòng)程序。實(shí)際上,在這里某些驅(qū)動(dòng)程序做了一些有關(guān)這條語(yǔ)句的事情。其他驅(qū)動(dòng)程序只是記住它,直到調(diào)用execute( ) 使這條語(yǔ)句被執(zhí)行為止。從prepare( ) 返回的值是一個(gè)語(yǔ)句句柄$ s t h,如果出現(xiàn)錯(cuò)誤,則為un d e f。在進(jìn)一步處理與這條語(yǔ)句相關(guān)的所有內(nèi)容時(shí),都使用這個(gè)語(yǔ)句句柄。
    請(qǐng)注意,指定的這個(gè)查詢(xún)沒(méi)有分號(hào)結(jié)束符。您無(wú)疑有這樣的(經(jīng)過(guò)長(zhǎng)時(shí)間使用mysql程序養(yǎng)成的)習(xí)慣,用‘ ;’字符終止sql 語(yǔ)句。然而,在使用dbi時(shí),最好打破這個(gè)習(xí)慣,因?yàn)榉痔?hào)經(jīng)常導(dǎo)致查詢(xún)出現(xiàn)語(yǔ)法錯(cuò)誤而失敗。向查詢(xún)?cè)黾印?/ g’也類(lèi)似,使用dbi 時(shí)不要這樣。
    在調(diào)用一個(gè)方法而不用向它傳遞任何參數(shù)時(shí),可以沒(méi)有這個(gè)圓括號(hào)。下列兩個(gè)調(diào)用是等價(jià)的:
    $sth->execute();
    $sth->execute;
    我寧愿有圓括號(hào),因?yàn)樗谷烁械竭@個(gè)調(diào)用看上去不像變量。您的選擇就可能不同了。
    調(diào)用execute( ) 后,可以處理成員列表的行。在dump_members 腳本中,提取行的循環(huán)簡(jiǎn)單地顯示了每行的內(nèi)容:

    fetchrow_array( ) 返回含有當(dāng)前行的列值的數(shù)組,在沒(méi)有剩余的行時(shí),返回一個(gè)空數(shù)組。這樣,此循環(huán)提取了由select 語(yǔ)句返回的連續(xù)行,并顯示列值之間用制表符分隔的每一行。在數(shù)據(jù)庫(kù)中null 作為undef 值返回到perl 腳本,但是將它們顯示為空字符串,而不是單詞“null”。
    請(qǐng)注意,制表符和換行符(表示為‘ / t’和‘/ n’)括在雙引號(hào)中。在perl 中,只解釋出現(xiàn)在雙引號(hào)內(nèi)的轉(zhuǎn)義符序列,不解釋出現(xiàn)在單引號(hào)內(nèi)的轉(zhuǎn)義符序列。如果使用單引號(hào),則輸出將為字符串“/ t”和“/ n”。
    提取行的循環(huán)終止以后,調(diào)用finish( ) 告知dbi 不再需要語(yǔ)句句柄,并且釋放分配給它的所有臨時(shí)資源。實(shí)際上,除非只提取結(jié)果集的一部分(無(wú)論是設(shè)計(jì)的原因,還是因?yàn)槌霈F(xiàn)一些問(wèn)題),否則不需要調(diào)用finish( )。然而,在提取循環(huán)之后, finish( ) 始終是很保險(xiǎn)的,我認(rèn)為調(diào)用并執(zhí)行finish( ),比區(qū)分何時(shí)需要,何時(shí)不需要更容易一些。
    我們已經(jīng)顯示完了全部成員列表,所以我們可以從服務(wù)器上斷開(kāi)連接,并且退出:
    $dbh->disconnect();
    exit(0);
    dump_members 示出了許多dbi 程序的大多數(shù)通用概念,而且不必了解更多的知識(shí),就可以著手編寫(xiě)自己的dbi 程序。例如,要想寫(xiě)出一些其他表的內(nèi)容,所需要做的只是更改傳遞給prepare( ) 方法的select 語(yǔ)句的文本。而且實(shí)際上,如果想了解這種技術(shù)的某些應(yīng)用,可略過(guò)這部分,直接跳到7 . 3節(jié)“運(yùn)行dbi”中討論如何生成歷史同盟一年一度的宴會(huì)成員列表程序和league 打印目錄的部分。然而,dbi 提供許多其他有用的功能。下一節(jié)介紹了一些,以便能夠在perl 腳本中看看如何完成比運(yùn)行一條簡(jiǎn)單的select 語(yǔ)句更多的事情。

處理錯(cuò)誤

    在dump_members 調(diào)用connect( )方法時(shí),應(yīng)該啟用raiseerror 錯(cuò)誤處理屬性,以便這些錯(cuò)誤用一條錯(cuò)誤消息就能自動(dòng)地終止相應(yīng)的腳本。也可以用其他方式處理這些錯(cuò)誤。例如,可以自己檢查錯(cuò)誤而不必使用dbi。
    為了查看如何控制dbi 的錯(cuò)誤處理行為,我們來(lái)仔細(xì)查看一下connect( ) 調(diào)用的最終參數(shù)。下面兩個(gè)相關(guān)的屬性是raiseerror 和p r i n t e r r o r:
    如果啟用r a i s e e r r o r(設(shè)為非零值),如果在dbi 方法中出現(xiàn)錯(cuò)誤,則dbi 調(diào)用die( ) 來(lái)顯示一條消息并且退出。
    如果啟用p r i n t e r r o r,在出現(xiàn)dbi錯(cuò)誤時(shí),dbi 會(huì)調(diào)用warn( ) 來(lái)顯示一條消息,但是相應(yīng)腳本會(huì)繼續(xù)執(zhí)行。
    缺省時(shí), raiseerror 是禁用的,而printerror 啟用。在此情況下,如果connect( )調(diào)用失敗,則dbi 顯示一條消息,而且繼續(xù)執(zhí)行。這樣,如果省略connect( ) 的四個(gè)參數(shù),則得到缺省的錯(cuò)誤處理行為,可以如下檢查錯(cuò)誤:
    $dbh=dbi->connect($dsn,$user_name,$password) or exit (1);
    如果出現(xiàn)錯(cuò)誤,則connect( ) 返回undef 表示失敗,并且觸發(fā)對(duì)exit( ) 的調(diào)用。因?yàn)閐bi 已經(jīng)顯示了錯(cuò)誤消息,所以您就不一定要顯示它了。
    如果明確給出該錯(cuò)誤檢查屬性的缺省值,可如下調(diào)用connect( )。
    $dbh=dbi->connect($dsn,$user_name,$password,{raiseerror=>0,printerror=>1})
    or exit (1);
    這就需要更多的編寫(xiě)工作,但是即使對(duì)不經(jīng)意的讀者,處理錯(cuò)誤行為也會(huì)更為明顯。
    如果想自己檢查錯(cuò)誤,并顯示自己的消息,應(yīng)該禁用raiseerror 和p r i n t e r r o r:

    變量$dbi::err 和$ dbi : :er r s t r,只用于所顯示的die( ) 調(diào)用中,有助于構(gòu)造錯(cuò)誤消息。它們含有mysql錯(cuò)誤代碼和錯(cuò)誤字符串,非常像c api 函數(shù)中的mysql_errno( ) 和mysql_error( )。
    如果僅僅要dbi 處理錯(cuò)誤,以便不必自己檢查它們,則啟用r a i s e e r r o r:
    $dbh=dbi->connect ($dsn,$user_name,$password,{raiseerror=>1});
    到目前為止,這是最容易的方法,并且是dump_members 帶來(lái)的。如果在腳本退出時(shí),想要執(zhí)行某種類(lèi)型的清除代碼,啟用raiseerror 可能是不恰當(dāng)?shù)模M管在這種情況下,可以重新定義$sig{_die_} 句柄,可以做想做的事情。
    避免啟用raiseerror 屬性的另一個(gè)原因是dbi 在它的消息中顯示技術(shù)信息,如下:
    disconnect(dbi::db=hash(0x197aae4)invalidates 1active statement.either
    destroy statement handles or call finish on them before disconnecting.
    對(duì)于編程者來(lái)說(shuō),這是好的信息,但對(duì)普通用戶(hù)可能沒(méi)有什么意義。在此情形,最好自己檢查錯(cuò)誤,以便可以顯示對(duì)期望使用這個(gè)腳本的人更有意義的消息?;蛘咭部稍谶@里考慮重新定義$sig{_die_} 句柄。這樣可能很有用,因?yàn)樗试S啟用raiseerror 來(lái)使錯(cuò)誤處理簡(jiǎn)單化,而不是用自己的消息替換dbi 給出的缺省錯(cuò)誤消息。為了提供自己的_die_ 句柄,可在執(zhí)行任何dbi 調(diào)用以前,進(jìn)行下面的工作:
    $sig{_die_}=sub{die "sorry,an error occurred/n";};
    也可以用普通的風(fēng)格定義一個(gè)子例程,并利用這個(gè)子例程的引用來(lái)設(shè)置這個(gè)句柄值:

    除了在connect( ) 調(diào)用中逐字傳遞錯(cuò)誤處理屬性之外,還可以利用散列定義它們,并傳遞對(duì)這個(gè)散列的引用。有人發(fā)現(xiàn)以這種方式準(zhǔn)備屬性設(shè)置使腳本更容易閱讀和編輯,但是在功能上這兩種方法是相同的。下面是一個(gè)說(shuō)明如何使用屬性散列的樣例:

    下面的腳本dump_members2 舉例說(shuō)明了當(dāng)要自己檢查錯(cuò)誤并顯示自己的消息時(shí),如何編寫(xiě)腳本。dump_member2 處理和dump_members 一樣的查詢(xún),但是明確地禁用printerror 和r a i s e e r r o r,然后測(cè)試每個(gè)dbi 調(diào)用的結(jié)果。如果出現(xiàn)錯(cuò)誤,在退出以前,腳本調(diào)用了子例程bail_out( ) 顯示消息及$dbi::err 和$dbi::errstr 的內(nèi)容:


    除了bail_out( ) 是退出而不是返回到調(diào)用者以外, bail_out( ) 類(lèi)似于我們?cè)诘?章中為編寫(xiě)c 程序使用的print_error( ) 函數(shù)。每次想顯示錯(cuò)誤消息時(shí), bail_out( ) 解除了寫(xiě)出$dbi::err 和$dbi::errstr 名稱(chēng)的麻煩。同樣,通過(guò)封裝顯示到子例程的錯(cuò)誤消息,可更改子例程使整個(gè)腳本中錯(cuò)誤消息的格式一致。
    dump_member2 腳本在提取行循環(huán)的后面有一個(gè)測(cè)試,這是dump_members 所沒(méi)有的。因?yàn)槿绻趂etchrow_array( ) 中出現(xiàn)錯(cuò)誤,dump_members2 不會(huì)自動(dòng)地退出,所以人們判斷循環(huán)是因?yàn)榻Y(jié)果集讀取完成而終止(正常終止),還是因?yàn)槌霈F(xiàn)錯(cuò)誤而終止做出確定是很困難的。當(dāng)然,任何一種方式,循環(huán)都將終止,但是如果出現(xiàn)錯(cuò)誤,則將刪截腳本的輸出。如果沒(méi)有錯(cuò)誤檢查,運(yùn)行該腳本的人將無(wú)法知道是否有錯(cuò)!如果自己檢查錯(cuò)誤,應(yīng)該檢查提取循環(huán)的結(jié)果。

處理不返回結(jié)果集的查詢(xún)

    d e l e t e、insert、replace和update等執(zhí)行后不返回行的語(yǔ)句比s e l e c t、describ、explain 和show 等執(zhí)行后返回行的語(yǔ)句的處理相對(duì)要容易一些。為處理一條非select 語(yǔ)句,利用數(shù)據(jù)庫(kù)句柄,將它傳遞給do( )。do( ) 方法在一個(gè)步驟內(nèi)準(zhǔn)備和執(zhí)行該查詢(xún)。例如,開(kāi)始輸入一個(gè)新的成員, marcis brown,終止日期為2002 年6 月3 日,可以這樣做:

    do( ) 方法返回涉及行的計(jì)數(shù),如果出現(xiàn)錯(cuò)誤,則返回un d e f。因?yàn)楦鞣N原因,可能出現(xiàn)錯(cuò)誤(例如,這個(gè)查詢(xún)可能是畸形的,或可能沒(méi)有訪問(wèn)這個(gè)表的權(quán)力)。對(duì)于非undef 的返回,注意那些沒(méi)有受到影響的行的情況。當(dāng)這種情況發(fā)生時(shí), do( ) 不返回?cái)?shù)字0;而是返回字符串“0 e 0”(0的perl科學(xué)計(jì)數(shù)法形式)?!? e 0”在數(shù)值上等價(jià)于0,但是,在條件測(cè)試中將其視為真,以便可以將其與早期的undef 區(qū)別。如果do( ) 返回0,則區(qū)分是出現(xiàn)了錯(cuò)誤( un d e f)還是“沒(méi)有受到影響的行”這兩種情況將更困難。使用下面的兩個(gè)測(cè)試之一可以檢查錯(cuò)誤:
    if (!defined ($rows)){#error}
    if (!$rows) {#error}
    在數(shù)值環(huán)境中,“0 e 0”與0 等價(jià)。下面的代碼將正確地顯示$rows 的任何非undef 值的行數(shù):

    也可以用printf( ) 使用‘% d’格式顯示$row 來(lái)強(qiáng)制進(jìn)行隱含的數(shù)字轉(zhuǎn)換:

    do( ) 方法等價(jià)于后跟execute( ) 的prepare( )。前面的insert 語(yǔ)句可以不調(diào)用do( ),如下發(fā)布:


處理返回結(jié)果集的查詢(xún)

    本章提供了有關(guān)實(shí)現(xiàn)select 查詢(xún)中提取行循環(huán)的若干選項(xiàng)的詳細(xì)信息(或其他類(lèi)似于select 的返回行的查詢(xún),如describ e、explain 和s h o w )。還討論了如何獲得結(jié)果中行數(shù)的計(jì)數(shù)值,如何處理不需要循環(huán)的結(jié)果集,以及如何一次檢索整個(gè)結(jié)果集的全部?jī)?nèi)容等。
    1. 編寫(xiě)提取行的循環(huán)
    dump_members 腳本利用dbi 方法的標(biāo)準(zhǔn)序列檢索數(shù)據(jù):prepare( ) 使驅(qū)動(dòng)程序處理查詢(xún),execute( ) 開(kāi)始執(zhí)行這個(gè)查詢(xún), fetchrow_array( ) 提取結(jié)果集中的每一行, finish( ) 釋放與這個(gè)查詢(xún)相關(guān)的資源。
    prepare( )、execute( ) 和finish( ) 是處理返回行的查詢(xún)中非常標(biāo)準(zhǔn)的部分。然而,對(duì)于提取的行,fetchrow_array( ) 實(shí)際上只是若干方法中的一種(請(qǐng)參閱表7 - 3)。

方法名返回值
fetchrow_array( )行值的數(shù)組
fetchrow_arrayref( )對(duì)行值數(shù)組的引用
fetch( )與fetchrow_arrayref( ) 相同
fetchrow_hashref( )對(duì)行值的散列引用,列名鍵索引

    下面的例子說(shuō)示出了怎樣使用每個(gè)提取行方法。這些例子在整個(gè)結(jié)果集的行中循環(huán),對(duì)于每一行,顯示由逗號(hào)分隔的列值。在某些情況下,編寫(xiě)這些顯示代碼還有一些更有效的方法,但是這些例子是以能夠說(shuō)明訪問(wèn)單個(gè)列值的語(yǔ)法的方式編寫(xiě)的。
    可如下使用fetchrow_array( ):

    對(duì)fetchrow_array( ) 的每個(gè)調(diào)用都返回行值數(shù)組,不再有行時(shí),返回一個(gè)空數(shù)組。
    選擇將返回值分配給數(shù)組變量,可以在一組標(biāo)量變量中提取列值。如果想使用比$ a r y [ 0 ]、$ary[1] 等更有意義的變量名,就可以這樣做。假設(shè)要在變量中檢索名稱(chēng)和電子郵件值,可使用fetchrow_array( ),可以如下選擇并提取行:

    當(dāng)然,在以這種方式使用一列變量時(shí),必須保證查詢(xún)按正確的次序選擇列。dbi 不關(guān)心select 語(yǔ)句指定列的次序,所以正確地分配變量是您的職責(zé)。在提取行時(shí),使用一種稱(chēng)為參數(shù)約束的技術(shù),也可以使列值自動(dòng)分配給單獨(dú)的變量。
    fetchrow_arrayref( ) 類(lèi)似于fetchrow_array( ),但不返回包含當(dāng)前行的列值的數(shù)組,而是返回這個(gè)數(shù)組的引用,在沒(méi)有乘余行時(shí),返回un d e f。如下使用:

    通過(guò)數(shù)組引用$ary_ref 訪問(wèn)數(shù)組元素。這類(lèi)似于引用指針,所以使用了$ary_ref->[$i] 而不是$ a r y [ $ i ]。要想引用整個(gè)數(shù)組,就要使用@{$ary_ref} 結(jié)構(gòu)。
    fetchow_arrayef( ) 不適合在列表中提取變量。例如,下面的循環(huán)不起作用:

    實(shí)際上,只要fetchrow_arrayref( ) 提取一行,這個(gè)循環(huán)就能正確地運(yùn)行。但是在沒(méi)有更多的行時(shí), fetchrow_arrayref( ) 返回un d e f,并且@{undef} 不合法(它有些像在c 程序中試圖廢棄一個(gè)null 指針)。
    提取行的第三個(gè)方法fetchrow_hashref( ),如下使用:

    對(duì)fetchrow_hashref( ) 的每個(gè)調(diào)用都返回一個(gè)按列名索引的行值散列的引用,在沒(méi)有更多的行時(shí),返回un d e f。在此情況下,列值不按特定的次序出現(xiàn); perl 散列的成員是無(wú)序的。然而,散列元素是按列名索引的,所以$hashref 提供了一個(gè)單獨(dú)的變量,可通過(guò)它按名稱(chēng)訪問(wèn)任何列值。這使得能按任意需要的次序來(lái)提取值(或者它們中的任何子集),而且不必知道select 查詢(xún)檢索的列的次序。例如,如果想訪問(wèn)名稱(chēng)和電子郵件域,可以如下進(jìn)行:

    如果希望將一行值傳遞給某個(gè)函數(shù)而又不需要這個(gè)函數(shù)知道select 語(yǔ)句中指定列的次序時(shí),fetchrow_hashref( ) 是非常有用的。既然如此,可以調(diào)用fetchrow_hashref( ) 來(lái)檢索行,并且編寫(xiě)一個(gè)使用列名訪問(wèn)來(lái)自行散列值的函數(shù)。
    如果使用fetchrow_hashref( ),請(qǐng)記住下列警告:
    如果性能很重要,則fetchrow_hashref( ) 并不是最好的選擇,因?yàn)樗鼪](méi)有fetchrow_array( ) 或fetchrow_arrayref( ) 的效率高。
    作為散列鍵值使用的列名具有與select 語(yǔ)句中寫(xiě)出時(shí)相同的字符。在mysql中,列名不區(qū)分大小寫(xiě),所以此查詢(xún)也是這樣,不管以大寫(xiě)字母還是小寫(xiě)字母給出列名,查詢(xún)結(jié)果都是一樣的。但是perl 散列索引名是區(qū)分大小寫(xiě)的,這可能會(huì)帶來(lái)一些問(wèn)題。為了避免潛在的大小寫(xiě)不匹配問(wèn)題,可通過(guò)傳遞name_lc 或name_uc 屬性,告知fetchrow_hashref( ) 強(qiáng)迫列名為大寫(xiě)或小寫(xiě):

    散列對(duì)每個(gè)唯一的列名含有一個(gè)元素。如果正在執(zhí)行從多個(gè)具有重疊名稱(chēng)的表中返回列的連接,則不能訪問(wèn)所有的列值。例如,如果發(fā)布下面的查詢(xún), fetchrow_hashref( )將返回只有一個(gè)元素的散列:
    select a.name from a,b where a.name=b.name
    2. 確定查詢(xún)返回的行數(shù)
    如何知道select 或類(lèi)似于select 的查詢(xún)返回的行數(shù)?一種方法是,當(dāng)提取它們時(shí),計(jì)算這些行的數(shù)量。實(shí)際上,這是知道select 查詢(xún)返回多少行的唯一方便的方法。使用mysql驅(qū)動(dòng)程序,可以在調(diào)用execute( ) 后利用語(yǔ)句句柄調(diào)用rows( ) 方法,但是這對(duì)其他數(shù)據(jù)庫(kù)引擎并不方便。而且即使就mysql來(lái)說(shuō),如果已經(jīng)設(shè)置了mysql_use_result 屬性,rows( ) 也不能返回正確的結(jié)果,直到提取了所有行(有關(guān)的詳細(xì)信息,請(qǐng)參閱附錄g)。所以只能如提取行一樣對(duì)它們進(jìn)行計(jì)數(shù)。
    3. 提取單行的結(jié)果
    如果結(jié)果集只含單個(gè)行,則不需要運(yùn)行循環(huán)來(lái)獲得結(jié)果。假設(shè)要編寫(xiě)得出歷史同盟成員當(dāng)前數(shù)量的腳本count _ member s。完成查詢(xún)的代碼如下所示:

    select 語(yǔ)句只返回一行,所以不需要循環(huán);我們只調(diào)用fetchrow_array( ) 一次。另外,因?yàn)槲覀冎贿x擇一列,所以甚至不需要將返回值分配給數(shù)組。當(dāng)在標(biāo)量環(huán)境中(單個(gè)值而不是所期望的一列)調(diào)用fetchrow_array( ) 時(shí),它返回這個(gè)行的第一列,如果沒(méi)有更多的有效行,則返回un d e f。
    另一種期望最多有一個(gè)記錄的查詢(xún)是一個(gè)含有l(wèi)imit 1來(lái)約束返回的行數(shù)的查詢(xún)。其一般的用法是返回特定列含有最大或最小值的行。例如,下面的查詢(xún)給出最近出生的總統(tǒng)姓名和出生日期:

    必須無(wú)提取循環(huán)的其他類(lèi)型的查詢(xún)利用max( ) 或min( ) 來(lái)選擇單個(gè)值。但是在所有這些情況下,獲得單個(gè)行結(jié)果的一種更容易的方法就是使用數(shù)據(jù)庫(kù)句柄方法selectrow_array( ),它結(jié)合了prepare( )、execute( ) 并在單個(gè)調(diào)用中提取行。它返回一個(gè)數(shù)組(而不是一個(gè)引用),如果出現(xiàn)錯(cuò)誤,則返回一個(gè)空數(shù)組。前一例子可利用selectrow_array( ) 編寫(xiě)如下:


    4. 處理完整的結(jié)果集
    在使用提取循環(huán)時(shí), dbi 不提供在結(jié)果集中隨意查找的方法,或以任何次序而不是以循環(huán)返回的次序來(lái)處理行。同樣,提取行以后,如果沒(méi)有保存,前一行會(huì)丟失。這種做法并不一定合適以下情況:
    以非連續(xù)的次序處理行??紤]一種情況,想以歷史同盟的president 表中列出的美國(guó)總統(tǒng)為主體,進(jìn)行一些測(cè)驗(yàn)。如果希望每次測(cè)驗(yàn)時(shí)都以不同的次序提出問(wèn)題,則可以從president 表中選擇所有行。然后,可能以任意的次序提取行來(lái)改變與所問(wèn)問(wèn)題有關(guān)的總統(tǒng)的次序。要想任意地提取一行,就必須同時(shí)訪問(wèn)所有的行。
    只使用返回行的子集,對(duì)其進(jìn)行隨機(jī)選擇。例如,當(dāng)問(wèn)及總統(tǒng)出生地時(shí),要想出現(xiàn)多個(gè)選擇的問(wèn)題,則可以隨便地提取一行來(lái)選擇總統(tǒng)(正確的答案),然后再?gòu)娜?lái)干擾的選擇中提取若干其他行。
    即使確實(shí)以連續(xù)的次序去處理,也想緊緊抓住整個(gè)結(jié)果集。如果想經(jīng)過(guò)這些行進(jìn)行多個(gè)傳遞,這可能是必需的。例如,在統(tǒng)計(jì)計(jì)算中,可能先瀏覽一遍結(jié)果集,來(lái)估計(jì)數(shù)據(jù)的一些通用數(shù)字屬性,然后再次檢查這些行,來(lái)實(shí)現(xiàn)更加明確的分析。
    可以用幾個(gè)不同的方式作為一個(gè)整體訪問(wèn)結(jié)果集??梢酝瓿蛇@個(gè)常見(jiàn)的提取循環(huán),并在提取它時(shí)保存每一行,可以使用一次返回整個(gè)結(jié)果集的方法。無(wú)論哪種方法都以在結(jié)果集中包括一行一行的矩陣作為結(jié)束,和選擇的列一樣多??梢砸匀魏未涡蛉我舛啻蔚靥幚砭仃嚨?br>元素。下面的討論說(shuō)明這兩種方法。
    使用提取循環(huán)來(lái)捕獲結(jié)果集的一種方法是使用fetchrow_array( ) 并保存對(duì)這些行引用的數(shù)組。除了保存所有的行,然后顯示矩陣舉例說(shuō)明了如何確定矩陣中的行數(shù)和列數(shù),及如何訪問(wèn)矩陣的個(gè)別成員以外,下面的代碼和dump_members 中提取和顯示的循環(huán)作用是一樣的。


    在確定矩陣的維數(shù)時(shí),必須首先確定行數(shù),因?yàn)闊o(wú)論這個(gè)矩陣是否為空,都可能計(jì)算列數(shù)。如果$rows 為0,則這個(gè)矩陣為空,并且$cols 也為0。否則,列數(shù)可能作為行數(shù)組中的元素?cái)?shù)量來(lái)計(jì)算,用語(yǔ)法@{$matrix[$i]} 來(lái)整體訪問(wèn)行$ i。
    在前述的樣例中, 我們提取每一行, 然后保存對(duì)它的引用??梢栽O(shè)想調(diào)用fetchrow_arrayref( ) 而不是直接地檢索行引用可能更有效率:

    它不能正常工作,因?yàn)閒etchrow_arrayref( ) 重新使用了引用指向的數(shù)組。結(jié)果矩陣是一個(gè)引用的數(shù)組,數(shù)組中的每個(gè)元素都指向相同行—最后檢索的行。因此,如果想一次提取一行,則要使用fetchrow_array( ) 而不是fetchrow_arrayref( )。
    另一個(gè)選擇是使用提取循環(huán),可以使用返回整個(gè)結(jié)果集的dbi 方法中的一個(gè)。例如,fetchall_arrayref( ) 返回對(duì)引用數(shù)組的引用,數(shù)組的每個(gè)元素都指向結(jié)果集中某行。這非常簡(jiǎn)單,但很有效,這個(gè)返回值是對(duì)矩陣的引用。要想使用fetchall_arrayref( ),則調(diào)用prepare( )和execute( ),然后如下檢索結(jié)果:

    如果結(jié)果集為空,則fetchall_arrayref( ) 返回一個(gè)對(duì)空數(shù)組的引用。如果出現(xiàn)錯(cuò)誤,則結(jié)果為un d e f,所以如果沒(méi)有啟用r a i s e e r r o r,則在開(kāi)始使用它以前,要確保檢查返回值。
    行數(shù)和列數(shù)由矩陣是否為空來(lái)確定。如果想作為一個(gè)數(shù)組訪問(wèn)這個(gè)矩陣的整個(gè)行$ i,應(yīng)該使用語(yǔ)法@ { $ m a t r i x _ r e f - > [ $ i ] }。
    使用fetchall_arrayref( ) 來(lái)檢索結(jié)果集當(dāng)然比編寫(xiě)一個(gè)提取行的循環(huán)要更簡(jiǎn)單一些,盡管訪問(wèn)數(shù)組元素的語(yǔ)法是一個(gè)小技巧。一個(gè)與fetchall_arrayref( ) 方法相類(lèi)似,但卻做了更多工作的方法是selectall_arrayref( )。這個(gè)方法為您完成了整個(gè)prepare( )、execute( )、提取循環(huán)、finish( ) 序列。為了使用selectall_arrayref( ),應(yīng)該利用數(shù)據(jù)庫(kù)句柄直接將查詢(xún)傳遞給它:

    5. 檢查null 值
    從數(shù)據(jù)庫(kù)中檢索數(shù)據(jù)時(shí),可能需要區(qū)分值為null 、為0 或者為空字符串的列。因?yàn)閐bi 返回null 列值作為un d e f,所以這種區(qū)分是容易的。然而,必須確保使用正確的測(cè)試。如果試用下面的代碼段,則它所有三次顯示都為“ f a l s e !”:

    而且,對(duì)于這兩個(gè)測(cè)試,這段代碼都顯示“ f a l s e !”:

    下面這段代碼效果相同:

    要想?yún)^(qū)分null 列值和非null 列值,則使用defined( )。知道了沒(méi)有出現(xiàn)null 值之后,使用適當(dāng)?shù)臏y(cè)試可以在其他類(lèi)型值之間加以區(qū)分。例如:

    以適當(dāng)?shù)拇涡蛲瓿蛇@些測(cè)試是很重要的,因?yàn)槿绻?#36;col_val 為空字符串,則第二個(gè)和第三個(gè)比較就都為真。如果顛倒比較的次序,則會(huì)錯(cuò)誤地將空字符串標(biāo)識(shí)為0。

引用問(wèn)題

    迄今為止,我們已經(jīng)利用引用字符串以最基本的方式構(gòu)造了查詢(xún)。在引用的字符串含有引用值時(shí),會(huì)在perl 詞匯一級(jí)產(chǎn)生問(wèn)題。在插入或者選擇含有引號(hào)、反斜杠或二進(jìn)制數(shù)據(jù)的值時(shí),在sql 中也可能出問(wèn)題。如果指定一個(gè)查詢(xún)作為perl 引用的字符串,則必須避免在查詢(xún)字符串本身中出現(xiàn)引用字符:

    perl 和mysql都允許用單引號(hào)或雙引號(hào)引用字符串,所以混合使用引用字符有時(shí)可以避免這種無(wú)法引用引用字符自身的情況:

    然而,在perl 中,這兩種類(lèi)型的引號(hào)并不等價(jià)。只有在雙引號(hào)內(nèi)部才解釋為變量引用。因此,當(dāng)想通過(guò)在查詢(xún)字符串中嵌入變量引用來(lái)構(gòu)造查詢(xún)時(shí),單引號(hào)并不是非常有用的。例如,如果$var 的值為14,則下面的兩個(gè)字符串并不等價(jià):

    兩個(gè)字符串的解釋如下所示;顯然,第一個(gè)字符串與希望傳遞給mysql服務(wù)器的內(nèi)容更為相像:

    用雙引號(hào)來(lái)引用字符串的另一個(gè)選擇是使用qq{} 結(jié)構(gòu),它告訴perl 在‘q q {’和‘}’之間的每個(gè)字符都要看作為雙引號(hào)括起的字符串(兩個(gè)q 表示“雙引號(hào)”)。例如,下列兩行是等價(jià)的:

    使用qq{} 時(shí),構(gòu)造查詢(xún)不用過(guò)多考慮引號(hào)的問(wèn)題,因?yàn)榭梢栽谶@個(gè)查詢(xún)字符串內(nèi)自由地使用引號(hào)(單引號(hào)或雙引號(hào)),而不用避開(kāi)它們。此外,還解釋了變量引用。qq{} 的這兩種特性可用下面的insert 語(yǔ)句來(lái)說(shuō)明:

    不一定使用‘ {’和‘ }’作為qq 的分隔符。其他格式,如qq( ) 和q q / /,也可以使用,只要封閉的分隔符不出現(xiàn)在字符串內(nèi)即可。我喜歡用q q { },因?yàn)椤?{’不像‘)’或‘/’會(huì)出現(xiàn)在查詢(xún)的文本內(nèi),并且在查詢(xún)字符串的結(jié)尾也可能有問(wèn)題。例如,‘)’出現(xiàn)在所顯示的insert 語(yǔ)句的內(nèi)部,所以qq( ) 對(duì)于引用查詢(xún)字符串來(lái)說(shuō)不是一個(gè)有用的結(jié)構(gòu)。
    qq{} 結(jié)構(gòu)能跨行,如果想讓查詢(xún)字符串在perl 代碼中醒目,這很有用:

    如果希望將查詢(xún)格式分為多個(gè)行,從而使它的可讀性更強(qiáng),這樣也很有用。例如,dump_members 腳本中的select 語(yǔ)句如下:

    用q q { }編寫(xiě)如下:


    雙引號(hào)字符串也可以跨行。但是,對(duì)于編寫(xiě)多行的字符串,我更喜歡用q q { }。我發(fā)現(xiàn)當(dāng)在一行中看到不匹配的引號(hào)時(shí),我就自然地去想,“這會(huì)是語(yǔ)法錯(cuò)誤嗎?”,然后,我就會(huì)浪費(fèi)時(shí)間去尋找相匹配的引號(hào)。
    qq{} 結(jié)構(gòu)在perl 詞匯級(jí)注意了引用的問(wèn)題,因此可將引號(hào)容易地放到字符串內(nèi),而不會(huì)使perl 搞混它們。然而,還必須考慮sql 級(jí)的語(yǔ)法??紤]向member 表中插入一條記錄:

    do( ) 發(fā)送給mysql的字符串如下所示:

    這是不合法的sql 語(yǔ)句,因?yàn)樵趩我?hào)字符串內(nèi)出現(xiàn)了單引號(hào)。在第6章中,我們遇到過(guò)類(lèi)似的引用問(wèn)題。在那里,我們使用mysql_escape_string( ) 來(lái)處理這個(gè)問(wèn)題。dbi 提供了一個(gè)類(lèi)似的機(jī)制—在一條語(yǔ)句中,對(duì)想按字面使用的每個(gè)引用值,都調(diào)用quote( ) 方法,并使用它的返回值。
    前面的例子可編寫(xiě)如下:

    現(xiàn)在,do( ) 發(fā)送給mysql的字符串如下所示,具有出現(xiàn)在引用字符串內(nèi)的可能對(duì)服務(wù)器轉(zhuǎn)義的引號(hào):

    請(qǐng)注意,在查詢(xún)字符串中引用$last 和$first 時(shí),不要增加括起來(lái)的引號(hào); quote( ) 方法支持它們。如果增加了引號(hào),則查詢(xún)將出現(xiàn)過(guò)多的引號(hào),如下面的例子所示:

    這些語(yǔ)句產(chǎn)生下面的輸出:


占位符和參數(shù)約束

    在前面各節(jié)中,我們通過(guò)把要插入或選擇的值作為選擇標(biāo)準(zhǔn),直接放在查詢(xún)字符串中構(gòu)造了查詢(xún)。不一定非要這樣做。dbi允許在查詢(xún)字符串內(nèi)部放置一些稱(chēng)為占位符的特殊標(biāo)記符,然后,在執(zhí)行該查詢(xún)時(shí),將這些值代替那些標(biāo)識(shí)符來(lái)使用。這樣做的主要原因是提高性能,特別是在循環(huán)中反復(fù)執(zhí)行某個(gè)查詢(xún)的時(shí)候。
    為了說(shuō)明占位符如何工作,舉例說(shuō)明。假設(shè)學(xué)校新學(xué)期剛開(kāi)始,打算清理學(xué)分薄的student 表,然后利用包含在文件中的一列學(xué)生姓名將其初始化,使其包含新學(xué)生。不用占位符,可以如下這樣刪除現(xiàn)有表的內(nèi)容,并裝入新的姓名:

    這樣做效率很低,因?yàn)閕nsert 查詢(xún)的基本格式每次都是相同的,并且在整個(gè)循環(huán)中,do( ) 每次都調(diào)用prepare( ) 和execute( )。在進(jìn)入這個(gè)循環(huán)以前,只調(diào)用一次prepare( ) 來(lái)設(shè)置insert 語(yǔ)句,并且在這個(gè)循環(huán)內(nèi)部只調(diào)用execute( ),這樣做效率更高一些。只調(diào)用一次prepare( ),可避免其他多次調(diào)用。dbi 允許我們這樣做:

    請(qǐng)注意這個(gè)insert 查詢(xún)中的‘ ?’就是一個(gè)占位符。調(diào)用execute( ) 時(shí),將查詢(xún)發(fā)送給服務(wù)器,傳遞這個(gè)值來(lái)代替占位符。一般來(lái)說(shuō),如果發(fā)現(xiàn)在循環(huán)內(nèi)部調(diào)用了do( ),應(yīng)該在循環(huán)前調(diào)用prepare( ),并在這個(gè)循環(huán)內(nèi)部調(diào)用execute( ) 更好一些。
    有關(guān)占位符的一些注意事項(xiàng):
    在查詢(xún)字符串內(nèi),不要在引號(hào)中封裝占位符字符。如果這樣做,不能識(shí)別為占位符。
    不要使用quote( ) 方法來(lái)指定占位符的值,否則將在插入的值中得到額外的引號(hào)。
    在查詢(xún)字符串中可以有一個(gè)以上的占位符,但是要確保占位符的標(biāo)記符與傳遞給execute( ) 的值一樣多。
    每個(gè)占位符都必須指定一個(gè)單獨(dú)的值,而不是一列值。例如,不能運(yùn)行這樣的語(yǔ)句:

    為了將null 指定為占位符,應(yīng)該使用un d e f。
    不要對(duì)關(guān)鍵字使用占位符。這樣會(huì)出問(wèn)題,因?yàn)檎嘉环闹凳怯蓂uote( ) 自動(dòng)處理的。
    關(guān)鍵字將被放在引號(hào)括起來(lái)的查詢(xún)中,因此,這個(gè)查詢(xún)會(huì)由于語(yǔ)法錯(cuò)誤而失敗。
    除了在循環(huán)中提高效率以外,對(duì)于某些數(shù)據(jù)庫(kù)引擎,可以從占位符的使用中獲得其他的性能好處。某些引擎高速緩存了準(zhǔn)備好的查詢(xún),以及為有效地運(yùn)行這個(gè)查詢(xún)所生成的計(jì)劃。也就是說(shuō),如果以后這個(gè)服務(wù)器收到同樣的查詢(xún),則它可以再次使用相應(yīng)的計(jì)劃而不用生成。查詢(xún)高速緩存特別有助于復(fù)雜的select 語(yǔ)句,因?yàn)榭赡苄枰ㄙM(fèi)時(shí)間生成較好的執(zhí)行計(jì)劃。占位符提供了一個(gè)在高速緩存中尋找查詢(xún)的好機(jī)會(huì),因?yàn)樗鼈兪共樵?xún)比直接在查詢(xún)字符串中嵌入指定的列值來(lái)構(gòu)造查詢(xún)更通用。對(duì)于mysql,在這種方式下,占位符并不提高性能,因?yàn)闆](méi)有高速緩存查詢(xún)。然而,可能仍想使用占位符編寫(xiě)自己的查詢(xún);如果偶然將dbi 腳本傳遞給支持查詢(xún)高速緩存的引擎,則這個(gè)腳本比沒(méi)有占位符時(shí)運(yùn)行效率更高。
    在查詢(xún)運(yùn)行時(shí),允許在查詢(xún)字符串中用占位符代替這些值。換句話說(shuō),可以參數(shù)化這個(gè)查詢(xún)的“輸入”。在提取行而不必將值賦給變量時(shí),dbi 也提供一個(gè)稱(chēng)為參數(shù)約束的輸出操作,允許通過(guò)檢索自動(dòng)進(jìn)入這些變量的列值使“輸出”參數(shù)化。
    假設(shè)有一個(gè)查詢(xún),檢索member 表中的成員姓名??梢愿嬖Vdbi 將選定列的值賦給perl變量。在提取行時(shí),變量利用相應(yīng)的列值自動(dòng)進(jìn)行更新。下面是一個(gè)例子,說(shuō)明如何將這些列約束到變量上,然后在提取循環(huán)中訪問(wèn)它們:

    bind_col( ) 的每個(gè)調(diào)用都應(yīng)該指定一個(gè)列號(hào)和一個(gè)希望與該列相聯(lián)的變量的引用。列號(hào)從1開(kāi)始。bind_col( ) 應(yīng)該在execute( ) 之后調(diào)用。
    還有一種選擇,就是單獨(dú)調(diào)用bind_col( ),可以在bind_columns( ) 的單個(gè)調(diào)用中傳遞全部變量引用:

指定連接參數(shù)

    建立服務(wù)器的連接的最直接的方法為,調(diào)用connect( ) 方法時(shí)指定所有連接參數(shù):

    如果遺漏連接參數(shù),則dbi 做下面的事情:
    如果未定義數(shù)據(jù)源或未定義空字符串,則使用dbi_dsn 環(huán)境變量。如果未定義用戶(hù)名和口令,則使用dbi_user 和dbi _ pass 環(huán)境變量(但如果它們?yōu)榭兆址畡t不使用)。在windows 下,如果未定義用戶(hù)名,則使用user 變量。
    如果遺漏了主機(jī)名,其缺省值為localhost。
    如果將用戶(hù)名指定為undef 或空字符串,則其缺省為unix 的登錄名稱(chēng)。在windows 下,用戶(hù)名缺省為odbc。
    如果將口令指定為undef 或空字符串,則不傳送口令。
    通過(guò)將某些選項(xiàng)添加到字符串的初始部分,每個(gè)都在分號(hào)前面,可以在數(shù)據(jù)源中指定這些選項(xiàng)。例如,可以使用mysql_read_default_file 選項(xiàng)來(lái)指定一個(gè)選項(xiàng)文件的路徑名:

    當(dāng)執(zhí)行這個(gè)腳本時(shí),它將從這個(gè)文件中讀取連接參數(shù)。假設(shè)/ u/ paul /.my.cnf 含有下面的內(nèi)容:

    然后connect( ) 調(diào)用試圖連接到p i t - v i per-snake-net 上的mysql服務(wù)器,并且用口令secret 及用戶(hù)名paul 連接。如果想允許具有正確地設(shè)置選項(xiàng)文件的任何人使用您的腳本,則像這樣指定數(shù)據(jù)源:

    $env{home} 含有用戶(hù)運(yùn)行這個(gè)腳本的主目錄的路徑名,所以這個(gè)腳本使用的主機(jī)名、用戶(hù)名和口令將會(huì)從每個(gè)用戶(hù)自己的選項(xiàng)文件中抽取出來(lái)。以這種方式編寫(xiě)腳本,不必在這個(gè)腳本中逐字地嵌入連接參數(shù)。
    還可以使用mysql_read_default_group 選項(xiàng),來(lái)指定一個(gè)選項(xiàng)文件組。這自動(dòng)地導(dǎo)致讀取用戶(hù)的.my.cnf 文件,并且除了[client] 組以外,還允許讀取一個(gè)指定的選項(xiàng)組。例如,如果在dbi 腳本中具有指定的選項(xiàng),則可以將它們列在[dbi] 組中,然后以如下方式使用數(shù)據(jù)源值:

    mysql_read_default_file 和mysql_read_default_group 需要mysql3.22.10 或更新的版本,以及dbd::mysql1.21.06 或更新的版本。有關(guān)指定的數(shù)據(jù)源字符串的選項(xiàng)的詳細(xì)信息,請(qǐng)參閱附錄g。有關(guān)mysql選項(xiàng)文件格式的詳細(xì)信息,請(qǐng)參閱附錄e。
    使用選項(xiàng)文件并不防礙在connect( ) 調(diào)用中指定連接參數(shù)(例如,如果想這個(gè)腳本作為特殊的用戶(hù)來(lái)連接)。在connect( ) 調(diào)用中指定的任何明確的主機(jī)名、用戶(hù)名和口令值都將覆蓋在選項(xiàng)文件中找到的連接參數(shù)。例如,想要腳本從命令行中分析- - host、--user 和--password 選項(xiàng),并使用那些值,如果給定,則優(yōu)先于在選項(xiàng)文件中發(fā)現(xiàn)的任何內(nèi)容。這是有用的,因?yàn)樗菢?biāo)準(zhǔn)的mysql客戶(hù)機(jī)操作的方式。dbi 腳本將因此符合它的行為。
    對(duì)于在本章中我們開(kāi)發(fā)的保留在命令行中的腳本,我將使用一些標(biāo)準(zhǔn)的連接設(shè)置代碼及卸載代碼。我只在這里說(shuō)明它一次,以便我們可以將精力集中在每個(gè)腳本的主體上,我們編寫(xiě)如下代碼:


    這個(gè)代碼初始化dbi,在命令行中查找連接參數(shù),然后使用命令行中的或者在用戶(hù)運(yùn)行這個(gè)腳本的- /.my.cnf 文件中所找到的參數(shù),連接到mysql服務(wù)器。如果在主目錄中設(shè)置.my.cnf 文件,則當(dāng)運(yùn)行這個(gè)腳本時(shí),不一定要輸入任何連接參數(shù)(請(qǐng)記住,設(shè)置這種方式,以便沒(méi)有其他人讀取這個(gè)文件。有關(guān)的指導(dǎo)請(qǐng)參閱附錄e)。
    我們腳本的最后部分也類(lèi)似于從腳本到腳本;它簡(jiǎn)單地終止這個(gè)連接并退出:
    $dhb->disconnect();
    exit (0);
    當(dāng)我們讀到web 程序設(shè)計(jì)的部分,即7 . 4節(jié)“在web 應(yīng)用程序中使用dbi”時(shí),將修改一些這個(gè)連接設(shè)置代碼,但是基本的思想是類(lèi)似的。

調(diào)試

    當(dāng)想調(diào)試有故障的dbi 腳本時(shí),通常使用兩項(xiàng)技術(shù),即單獨(dú)使用一個(gè)或一前一后地配合使用。首先,在腳本的整個(gè)過(guò)程中編寫(xiě)顯示語(yǔ)句。它允許將自己調(diào)試的輸出設(shè)計(jì)為想要的方式,但必須手工地增加語(yǔ)句。其次,可以使用dbi 的內(nèi)建跟蹤能力。這更加通用,但也更加
系統(tǒng),而且它在打開(kāi)以后,則會(huì)自動(dòng)地出現(xiàn)。dbi 跟蹤也說(shuō)明一些除此以外就無(wú)法獲得的有關(guān)驅(qū)動(dòng)程序的操作信息。
    1. 使用顯示語(yǔ)句調(diào)試
    在mysql郵件清單中,常見(jiàn)問(wèn)題之一是:“有一個(gè)查詢(xún),當(dāng)我在mysql中執(zhí)行它時(shí)運(yùn)行得很好,但是它不能在我的dbi 腳本中工作,怎么回事?”尋找發(fā)布不同查詢(xún)的dbi 腳本和這個(gè)發(fā)問(wèn)者所期望的一樣是很平常的。如果在執(zhí)行它之前顯示查詢(xún),則可能會(huì)驚異地看到真
正發(fā)送到這個(gè)服務(wù)器上的內(nèi)容。假設(shè)將一個(gè)查詢(xún)鍵入到mysql中(沒(méi)有終止的分號(hào))

    然后,在dbi 腳本中試著做相同的事情:

    盡管它是同樣的查詢(xún),但它不能工作。不是嗎?試著顯示:
    print "$query/n"
    結(jié)果如下:
    insert member (last_name,first_name,expiration)
    values(brown,warcia,2002-6-3)
    從這個(gè)輸出中,可以看到是您忘記了values( ) 列表中這些列值前后的引號(hào)。指定查詢(xún)的正確方法如下:

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

    不幸的是,當(dāng)做這些的時(shí)候,使用顯示語(yǔ)句不能看到完整查詢(xún)的樣子,因?yàn)橹钡秸{(diào)用d o ( )才能估計(jì)占位符的值。當(dāng)使用占位符時(shí),跟蹤可能對(duì)調(diào)試方法更有幫助。
    2. 使用跟蹤調(diào)試
    當(dāng)試圖查出腳本不能正確工作的原因時(shí),可以告知dbi 來(lái)生成跟蹤(調(diào)試)信息。跟蹤級(jí)別范圍從0(關(guān)閉)到9(最多信息)。一般來(lái)說(shuō),跟蹤級(jí)別1和2 是最有用的。級(jí)別2 跟蹤說(shuō)明正在執(zhí)行的查詢(xún)文本(包括占位符替換的結(jié)果)、調(diào)用quote( ) 的結(jié)果等等。這可能對(duì)捕獲問(wèn)題有極大的幫助。
    使用trace( ) 方法,可以從獨(dú)立的腳本內(nèi)部控制跟蹤,或者可以設(shè)置dbi_trace 環(huán)境變量來(lái)影響所運(yùn)行的所有dbi 腳本的跟蹤。
    要想使用trace( ) 調(diào)用,則傳遞一個(gè)跟蹤級(jí)別參數(shù),并可以有選擇地再傳遞一個(gè)文件名。如果沒(méi)有指定文件名,則所有的跟蹤輸出到stderr 中;否則,它就轉(zhuǎn)到這個(gè)命名的文件中。一些樣例如下:

    當(dāng)調(diào)用dbi->trace( ) 時(shí),跟蹤所有的dbi 操作。一個(gè)更精細(xì)的方法是,可以用獨(dú)立的處理級(jí)別啟用跟蹤。當(dāng)沒(méi)想好腳本中問(wèn)題的位置,并對(duì)在那點(diǎn)出現(xiàn)的每件事的跟蹤輸出不想插手時(shí),這是有幫助的。例如,如果特定的select 查詢(xún)有問(wèn)題,則可以跟蹤與這個(gè)查詢(xún)相關(guān)的語(yǔ)句句柄:

    如果對(duì)任何trace( ) 調(diào)用指定一個(gè)文件名參數(shù),則無(wú)論對(duì)dbi 作為整體還是單獨(dú)的句柄,所有的跟蹤輸出都要到那個(gè)文件中。
    要想對(duì)運(yùn)行的所有dbi 腳本全部都打開(kāi)跟蹤,則從命令解釋程序中設(shè)置dbi_trace 環(huán)境變量。它的語(yǔ)法取決于使用的命令解釋程序:

    value 的模式和所有命令解釋程序的模式一樣:數(shù)字n表示在級(jí)別n打開(kāi)跟蹤到s t d e r r中;文件名打開(kāi)級(jí)別2 跟蹤到這個(gè)命名的文件,或n=file_name 打開(kāi)級(jí)別n跟蹤到這個(gè)命名的文件中。下面的樣例使用了csh 語(yǔ)法:

    如果打開(kāi)跟蹤到命令解釋程序中的文件,則確保一旦解決了這個(gè)問(wèn)題,就將它關(guān)閉。將調(diào)試輸出增加到這個(gè)跟蹤文件中,而不用重寫(xiě)它,所以如果不小心,則這個(gè)文件可能變得非常大。極其不好的想法是在命令解釋程序的啟動(dòng)文件(如.cshrc、.lonin 或. p r o f i l e)中定義dbi _ t r a c e!在unix 下,可以使用下面兩個(gè)命令( csh 語(yǔ)法)之一關(guān)閉跟蹤:
    % setenv dbi_trace 0
    % unsetenv dbi_trace
    對(duì)于s h、ksh 或b a s h,這樣做:
    $ dbi_trace=0
    $export dbi_trace
    在windows 操作系統(tǒng)中,可以使用下面兩個(gè)命令之一關(guān)閉跟蹤:
    c:/>unset dbi_trace
    c:/>set dbi_trace=0

使用結(jié)果集元數(shù)據(jù)

    可以使用dbi 來(lái)獲得訪問(wèn)結(jié)果集元數(shù)據(jù)——也就是有關(guān)由查詢(xún)選擇行的描述信息。訪問(wèn)與結(jié)果集生成的查詢(xún)所相關(guān)的語(yǔ)句句柄的屬性來(lái)獲得這個(gè)信息。提供這些屬性中有一些是作為可用于橫跨所有數(shù)據(jù)庫(kù)驅(qū)動(dòng)程序的標(biāo)準(zhǔn)dbi 屬性(如n u m _ o f _ f i e l d s,結(jié)果集中列的數(shù)量)。另外一些是mysql特定的,由dbd::mysql所提供的dbi 的mysql驅(qū)動(dòng)程序。這些屬性,如mysql_max_length 告知了每列值的最大寬度,不能用于其他數(shù)據(jù)庫(kù)引擎。要想使用任何mysql特定的屬性,都必須冒著使腳本不可移植到其他數(shù)據(jù)庫(kù)的危險(xiǎn)。另一方面,它們可以使它更容易地獲得想要的信息。
    必須在適當(dāng)時(shí)候請(qǐng)求元數(shù)據(jù)。一般來(lái)說(shuō),直到調(diào)用prepare( ) 和execute( ) 之后,結(jié)果集屬性才能用于select 語(yǔ)句。除此之外,在調(diào)用finish( ) 之后,屬性可能變?yōu)闊o(wú)效。
    讓我們來(lái)看看如何使用mysql的一個(gè)元數(shù)據(jù)屬性mysql_ m a x _ l e n g t h,與保留查詢(xún)列名的dbi 級(jí)別的name 屬性一起使用。我們可以將這些屬性提供的信息合并起來(lái),編寫(xiě)一個(gè)腳本b o x _ o ut,它以交互模式運(yùn)行mysql客戶(hù)機(jī)程序時(shí)獲得的相同邊框風(fēng)格,從select 查詢(xún)產(chǎn)生輸出。box_out 的主體如下(可以用任何其他的語(yǔ)句替換select 語(yǔ)句;編寫(xiě)輸出的例程獨(dú)立于特定的查詢(xún)):


    用execute( ) 將這個(gè)查詢(xún)初始化之后,我們獲得了所需的元數(shù)據(jù)。$sth->{name} 和$ s t h ->{mysql_max_length} 給出了列名和每列值的最大寬度。為了在這個(gè)查詢(xún)中為列命名,每個(gè)屬性值都引用了一個(gè)數(shù)組,這個(gè)數(shù)組含有結(jié)果集每列中的一個(gè)值。
    剩余的計(jì)算非常類(lèi)似于在第6章中開(kāi)發(fā)的客戶(hù)機(jī)程序5中所使用的那些內(nèi)容。例如,為避免偏離輸出,如果列的名比該列中任何數(shù)據(jù)值都寬,則我們要向上調(diào)整列的寬度值。
    輸出函數(shù)print_dashes( ) 和print_row( ) 代碼編寫(xiě)如下,它們也類(lèi)似于客戶(hù)機(jī)程序5中相應(yīng)的代碼:

    box_out 的輸出如下:

    我們的下一個(gè)腳本使用了列元數(shù)據(jù)來(lái)產(chǎn)生不同格式的輸出。這個(gè)腳本s h o w _ member,允許快速瀏覽歷史同盟成員項(xiàng)目,而不用輸入任何查詢(xún)。給出成員的姓,它就這樣顯示所選擇的項(xiàng)目:


    使用成員資格號(hào)碼,或者使用與若干姓相匹配的模式也可以調(diào)用s h o w _ member s。下面的命令說(shuō)明成員號(hào)碼為2 3的項(xiàng)目,和以字母“c”開(kāi)始的姓的成員項(xiàng):

    show_member 腳本的主體如下所示。它使用了name 屬性來(lái)確定輸出的每行所使用的標(biāo)號(hào)和num_of_fields 屬性,找出這個(gè)結(jié)果集含有的列數(shù):


    無(wú)論區(qū)域是什么, show_member 的目的都是說(shuō)明一個(gè)項(xiàng)目的全部?jī)?nèi)容。通過(guò)使用select * 來(lái)檢索所有的列和name 屬性來(lái)看看它們是什么,即使從member 表中增加或刪除列,這個(gè)腳本也會(huì)工作而不用做修改。
    如果不檢索任何行就想知道一個(gè)表含有哪些列,則可以發(fā)布下面這條查詢(xún):
    select * from tbl_name where 1=0
    以正常方式調(diào)用prepare( ) 和execute( ) 之后,可以從@{$sth->{name}} 中得到列名。然而,請(qǐng)注意,盡管使用“空”查詢(xún)的這個(gè)小竅門(mén)可以在mysql下運(yùn)行,但是它不可移植,而且并不是對(duì)所有的數(shù)據(jù)庫(kù)引擎都可以工作的。
    有關(guān)dbi 和dbd::mysql所提供屬性的詳細(xì)信息,請(qǐng)參見(jiàn)附錄g。它完全可以使您確定是想通過(guò)避免mysql特定的屬性而為可移植性花費(fèi)努力,還是在可移植性的開(kāi)銷(xiāo)方面利用它們。

發(fā)表評(píng)論 共有條評(píng)論
用戶(hù)名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
国产69精品久久久久孕妇| www.黄色小说.com| 午夜av电影一区| 精品久久久av| 国产精品亚洲一区二区三区| 国产精品一区在线免费观看| 色多多视频在线观看| 久久久一区二区三区不卡| 亚洲熟女乱综合一区二区| 亚洲啊v在线观看| 中文字幕在线三区| 免费网站在线观看人| 国产在线观看精品一区| 在线观看美女网站大全免费| 91美女精品福利| 久久久亚洲国产天美传媒修理工| 国产福利片一区二区| 精品无人区卡一卡二卡三乱码免费卡| 波多野结衣电影免费观看| www.中文字幕在线观看| 秘密影院久久综合亚洲综合| 5g国产欧美日韩视频| 波多野结衣一本| 亚洲最大福利视频网| 国产精品久久久久蜜臀| 久久久精品国产一区二区| 国产69精品久久app免费版| 噜噜噜在线观看免费视频日韩| 亚洲福利在线观看视频| 少妇av在线| 91在线播放网址| 亚洲欧美另类视频| 精品91福利视频| 国产毛片在线视频| 一级黄色电影片| 中文字幕日产av一二三区| 中文字幕亚洲精品在线观看| 日韩免费视频一区| 91在线品视觉盛宴免费| 亚洲一区二区三区在线观看网站| 高清免费电影在线观看| 国产特级黄色大片| 91超碰在线免费| 亚欧黄色av| 国产精品精品久久久久久| 海角社区69精品视频| 荡女精品导航| 亚洲成年人在线观看| 国产按摩一区二区三区| 91高清视频在线| 国产蜜臀一区二区打屁股调教| 久久福利一区| 日韩精品一区二区三区av| 国产麻豆视频精品| 91在线精品入口| 亚洲一级av无码毛片精品| 一本一本久久a久久综合精品蜜桃| 欧美xxx视频| 国产夫妻性生活视频| 日韩av电影免费在线观看| 精品一区二区三区在线播放| 男人添女荫道口女人有什么感觉| 国产欧美亚洲精品| 国产chinasex对白videos麻豆| 8v天堂国产在线一区二区| 色先锋影音岛国av资源| 亚洲一区三区视频在线观看| www五月天com| 电影91久久久| 黄一区二区三区| eeuss鲁片一区二区三区在线观看| 国内老熟妇对白xxxxhd| 亚洲精品天堂网| 成人超碰在线| 蜜桃麻豆www久久国产精品| 中文字幕一区二区人妻痴汉电车| 亚洲毛片视频| 美女被搞网站| 欧美videos粗暴| 91.·福利| 成+人+亚洲+综合天堂| 国产婷婷精品| 成人av在线播放网址| 国产精品免费一区二区三区| 嫩草香蕉在线91一二三区| 翔田千里亚洲一二三区| 亚洲一区三区电影在线观看| 伊人一区二区三区| 草草视频在线播放| 91免费人成网站在线观看18| 午夜免费福利影院| 欧美日韩中字一区| 国产福利一区二区三区在线播放| 欧美一区二区三区四区久久| 日韩av电影在线免费播放| 久久亚洲精精品中文字幕| 欧美电影免费观看| 91精品中文字幕一区二区三区| 欧美成人激情| 一区二区三区四区不卡在线| 欧美另类69xxxx| 国产精品一区一区| 自拍视频在线免费观看| 亚洲日本japanese丝袜| 国产日产精品一区二区三区的介绍| 国产精品一区二区三区四区色| 天使と恶魔の榨精在线播放| 99国内精品久久久久久久| 日本一级在线观看| 韩国av免费观看| 男女视频在线观看网站| 老熟妇精品一区二区三区| 久久国产情侣| 人人妻人人藻人人爽欧美一区| 一级黄色特级片| 啊v视频在线一区二区三区| 久久精品五月婷婷| 91网免费观看| 日本精品一区二区在线观看| 欧美日韩国产一区二区| 国产免费视频在线| 青青草国产在线观看| 亚洲乱码国产乱码精品精| 欧美午夜免费电影| www.黄色av| 国产精品裸体一区二区三区| 天天色影综合网| 97成人超碰免| 青草久久伊人| 香蕉久久久久久av成人| 少妇饥渴放荡91麻豆| 97超级碰碰人国产在线观看| 精品一区二区三区在线观看l| 国产成人免费av在线| 欧美大黄免费观看| 人人九九精品视频| 免费又爽又黄禁片视频1000片| 亚洲一级片在线看| 久久亚洲欧美国产精品乐播| 最新黄网在线观看| 香蕉视频一区二区三区| 波多野结衣在线中文| 西野翔中文久久精品字幕| 日韩欧美国产成人精品免费| 亚洲国产精品免费| 日本美女一区二区三区| 奇米精品一区二区三区四区| 欧美xxxx综合视频| 九九热视频免费观看| 国产精品高潮呻吟久久av野狼| 精品中文字幕一区二区三区av| 国产麻豆综合| 国产精品你懂的在线欣赏| 欧美精品v日韩精品v韩国精品v| 亚洲欧美久久久久| 91精品视频网站| 亚洲午夜电影网| 日韩欧美一区电影| 亚洲欧美日韩中文播放| 中文字幕一区二区三区四区免费看| 91高清视频在线免费观看| 91热福利电影| va中文字幕| 欧美色综合天天久久综合精品| 久久最新免费视频| 免费福利视频网站| 在线观看中文字幕亚洲| 欧美激情一二三区| 亚洲视频免费在线观看| 日韩专区欧美专区| 亚洲免费av网站| 91精品国产高清久久久久久久久| 色噜噜狠狠色综合网| 亚洲黄网在线观看| 国产午夜精品久久久久久久久| 国产真实乱全部视频| 成人精品国产一区二区4080| 91av在线免费观看视频| 精品人妻一区二区三区四区| 欧美日韩中文字幕一区二区三区| 日韩欧美国产骚| 国产精品亚洲一区二区三区在线| 精品久久久久久中文字幕人妻最新| 日韩美女国产精品| 日韩伦理一区二区三区| 99久久精品日本一区二区免费| 这里只有精品视频在线观看| 久久久久九九九九| 午夜看片在线免费| 91九色02白丝porn| 国产一区在线不卡| 粉嫩av亚洲一区二区图片| 久久国产精品露脸对白| 98视频精品全部国产| 中国国产一级毛片| 精品国产免费人成网站| 欲求不满的岳中文字幕| 一本一本久久a久久精品综合小说| 二区三区中文字幕| 国产亚洲一区字幕| 欧美另类videosbestsex日本| 黑人巨大精品| 欧美成人午夜| 深爱激情综合网| 99热6这里只有精品| 日韩黄色一区二区| 久久青草欧美一区二区三区| 久久久精品人妻一区二区三区| 四虎地址8848jia| 亚洲尤物av| 激情小说综合区| 久久男人天堂| 国产伦子伦对白在线播放观看| 国产免费区一区二区三视频免费| 欧美精品国产白浆久久久久| 欧美性猛交xxxx免费看蜜桃| 国模私拍在线观看| 成人精品国产免费网站| 欧美日韩亚洲一区二区| 日韩1区2区3区| 久草在线中文888| 99热99精品| 91av com| 国产女优在线播放| 青草国产精品久久久久久| 免费av不卡在线观看| 国产成人精品一区二区三区视频| 在线观看日韩欧美| 国产在线播放一区三区四| 草莓视频成人appios| 黄色大片在线看| 欧美日本一区二区视频在线观看| 久久久久国产精品一区三寸| 椎名由奈jux491在线播放| 国内精品国语自产拍在线观看| 亚洲国产美女久久久久| 国产一区二区三区不卡av| 国产欧美一区二区| 国产伦理一区二区| 亚洲精品在线免费播放| 日本一区二区欧美| 欧美人善zozσ性伦交| 国产精品一区二区三区在线免费观看| 免费日本一区二区三区视频| 亚洲国产精品一区二区第四页av| 久久免费电影| 色诱色偷偷久久综合| 色综合久久网| 欧美成人黑人xx视频免费观看| 国产精品一区二区无码对白| 无码av中文一区二区三区桃花岛| 精品无人国产偷自产在线| 毛片大全在线观看| 精品自拍偷拍| a级毛片免费观看在线| 韩国在线一区| 五月天婷婷综合网| 成人av在线网址| 中文在线天堂库| av大片在线免费观看| 欧美最猛性xxxxx亚洲精品| 黄色免费网站观看| 中文字幕久久av| 粉色视频免费看| 成人激情电影一区二区| 日韩精品免费一区二区夜夜嗨| 麻豆国产精品一区| 久久久久久久久久久久av| 国产女王在线**视频| 免费电影视频在线看| 欧美日本韩国国产| 日韩视频在线一区二区| 99re热视频| 国产精品日日摸夜夜添夜夜av| 一区二区国产在线观看| 欧美人在线视频| 日韩中文有码在线视频| 亚洲精品在线不卡| 最近免费中文字幕大全免费第三页| 中文字幕欧美区| 91精品视频网| 国产一区二区三区小说| 久久综合网络一区二区| 国产日韩高清在线| 欧美亚洲激情| 红桃视频在线观看一区二区| 在线观看www91| 日本久久二区| 爱爱免费视频网站| 91video| 亚洲免费av网| 国产精品字幕| 国产伦精品一区二区三区免.费| www.四虎网站| 欧美亚洲日本在线观看| 日韩成人三级视频| 精品对白一区国产伦| 久久久久久久久岛国免费| 亚洲第一se情网站| 日韩高清不卡一区二区| 国产又粗又黄视频| 国产suv精品一区二区6| 嫩草香蕉在线91一二三区| 国产又黄又爽又色| 国产视频精品一区二区三区| 色婷婷av一区二区三区在线观看| 三级福利片在线观看| 日韩成人av影视| 天堂av一区二区三区在线播放| 国产精品一区二区三区在线免费观看| 欧美午夜精品在线| 欧美**字幕| 精品少妇一区二区30p| 一级做a爰片性色毛片视频| 中字幕一区二区三区乱码| 日本一二三不卡视频| 色综合天天综合网中文字幕| 性生活视频网站| 久久婷婷成人综合色| 国产精品一区二区久久不卡| 日韩欧美专区在线| 日韩视频在线观看一区二区| 翁止熄痒禁伦短文合集免费视频| 影音日韩av| 亚洲一区二区自拍偷拍| 欧美一级特黄aaaaaa大片在线观看| 亚洲电影在线| 大胆人体一区二区|