Perl與數據庫DBI快速入門

Perl與數據庫DBI快速入門

上次的文章Perl無廢話入門指南中,簡單的介紹了Perl的開發環境。爲了完成提到的任務,還須要作幾個知識點。不管是寫腳本仍是作CGI,如何使用Perl來訪問數據庫就是頗有用的一個知識。html

各類語言和開發環境訪問數據庫有各類不一樣的方式,好比能夠用C和數據庫提供的API接口來進行訪問,也能夠用JDBC、ODBC、ADO等封裝好的統一接口來進行訪問。Perl訪問數據庫最經常使用的包是DBI,能夠在www.cpan.org找到。另外還須要安裝對應數據庫的驅動包,例如DBD::MySQL、DBD::Oracle、DBD::Sybase或者DBD::ODBC等。具體的安裝方法請參考上期文章,在此就不贅述了。mysql

下文以常見的MySQL爲例,說說如何實現對數據庫的操做。程序員

1 基本流程

習慣在Windows下開發數據庫、熟悉ADO、ADO.NET的朋友,必定對ADOConnection/ADODataSet/ADOTable等類耳熟能詳。DBI的接口與之相似,但在操做方法上又有不一樣,對ADO熟悉的朋友不妨比較一下異同。通常來講,數據庫操做由如下幾個步驟組成一個常見的流程:sql

1. 創建一個數據庫鏈接數據庫

2. 經過創建的數據庫鏈接,執行SQL語句編程

3. 執行SQL後獲取返回的數據集數組

4. 在數據集中對記錄進行處理,通常是一個循環的過程服務器

5. 處理完畢,關閉數據庫鏈接,釋放資源oracle

下面是按照上述的流程,在Perl中訪問MySQL的一段代碼,以這段代碼爲例,詳細說明DBI的使用方法。性能

#!/usr/bin/perl -w
use strict;
use DBI;

my $dbh = DBI->connect("DBI:mysql:test:192.168.1.2", 'root', 'password');
my $sth = $dbh->prepare("SELECT * FROM test1");
$sth->execute();

while ( my @row = $sth->fetchrow_array() )
{
       print join('\t', @row)."\n";
}

$sth->finish();
$dbh->disconnect();

注意代碼中的灰色部分就是要特別關注的數據庫訪問接口,這裏展示的只是一部分,下面將會依次說明每個步驟,以及其它的操做在Perl中是如何實現的。

1.1 鏈接數據庫

my $dbh = DBI->connect("DBI:mysql:test:192.168.1.2", 'root', 'password');

調用DBI的方法DBI->connect來創建一個數據庫的鏈接,若是鏈接成功則返回一個數據庫鏈接句柄,以後執行SQL等操做都要把這個鏈接句柄做爲一個操做參數。在connect調用中,首先要提供一個數據庫鏈接串。這個鏈接串用冒號分爲了幾個部分,請看下錶

 

 

 

 

 

 

 

 

 

 

 

小節 說明
DBI 接口類型
mysql 數據庫類型
test 數據庫名稱
192.168.1.2 數據庫主機地址

 

在前面例子中的鏈接串中,DBI表示這是DBI接口的一個鏈接串;mysql表示要鏈接的數據庫是MySQL數據庫(若是要鏈接Oracle數據庫,這裏則是oracle),不一樣的數據庫有不一樣的鏈接串定義,能夠參考DBI對應的訪問驅動的說明;test指明瞭鏈接到數據庫主機上的數據庫名稱;192.168.1.2就是MySQL服務器的IP地址。這裏要注意的是,鏈接串中的數據庫類型mysql必須小寫。若是省略了主機名,則缺省爲localhost。connect方法的後面兩個參數是鏈接數據庫主機的用戶名和密碼,這個但是不可缺乏的 J

若是在鏈接過程當中出現任何錯誤,則connect的返回值都會是undef(和C語言中的NULL是一回事)。這裏爲了簡化而略去了錯誤檢查,實際作項目的時候應當對這些錯誤和返回值的進行檢查。

1.2 執行SQL語句

my $sth = $dbh->prepare("SELECT * FROM test1");
$sth->execute();

$dbh->do(「UPDATE test1 SET time=now()」);

鏈接上了數據庫,得到了數據庫鏈接句柄,就能夠利用這個句柄來對數據庫進行操做了。要執行一條SQL語句,爲了提升性能,DBI分兩個步驟來作。先把SQL語句經過prepare方法提交到數據庫,數據庫爲該語句分配執行資源,以後調用execute方法通知數據庫執行該SQL語句。注意prepare方法是經過數據庫鏈接句柄調用的,若是成功則返回一個該SQL的句柄,以後經過該SQL語句句柄調用execute執行SQL。 通常來講execute執行的都是返回數據的語句(例如SELECT語句)。反之若是執行INSERT、UPDATE、DELETE、CREATE TABLE等不須要返回數據的語句,則有一個更方便、快速的方法 $dbh->do(SQL語句),能夠省去prepare的步驟。do方法返回的是受該SQL影響的記錄數量。

1.2.1 技巧:對SQL進行排版

常寫大段SQL的朋友可能會對於SQL中的引號很頭痛,往往都由於引號的問題搞的SQL語句亂成一團分辨不清。還記得上篇文章講過的qq嗎?這裏正是它的好用處。因爲qq中的字符串同雙引號」 」內的字符串同樣會對變量進行解釋,同時qq還能夠換行。所以使用它來對SQL進行排版是很是好的一個選擇,例如像這樣的一條SQL語句:

my $res_operator = $dbhandle->prepare( qq{
       SELECT o_customerid, COUNT(*) AS totalMsgNum FROM mm4fcdrs
       WHERE (m_date>'$begindate') AND (m_date<'enddate') 
       GROUP BY o_customerid 
});

根本無需考慮引號的問題,能夠和正常狀況同樣的寫SQL,是否是方便了不少?

1.2.2 經過SQL語句中的參數優化查詢執行效率

在執行大量INSERT之類的語句的時候,反覆向數據庫服務器提交一樣結構的一個SQL語句,在這種狀況下能夠利用prepare和SQL參數來優化執行效率:

1.先使用prepare提交一個SQL模板給數據庫服務器,把其中值的部分用參數佔位符代替。 2.使用prepare讓服務器爲該SQL準備了執行資源後,調用execute並在該方法中傳入參數實際的值執行SQL。 3.以後能夠反覆調用execute,不須要服務器從新prepare

假設要執行這樣的一個系列的SQL

INSERT INTO test1 VALUES (NULL, ‘a’, ‘2005-04-01’)
... ...
INSERT INTO test1 VALUES (NULL, ‘z’, ‘2005-04-01’)

其中第二個字段的值是從a到z的字母。那麼能夠這樣來優化執行效率:

my $sth = $dbh->prepare( qq{
    INSERT INTO test1 VALUES (NULL, ?, ‘2005-04-01’)
} );

for my $value('a'..'z')  {
    $sth->execute($value);
}

其中的問號就是前面說的參數佔位符了,它的意思就是告訴在準備執行資源的服務器:這個SQL的這個位置會有一個值,可是如今還不知道,等下執行的時候再告訴你。 prepare了以後,用一個循環產生a-z的字符給變量$value,而後將$value在execute方法中做爲一個參數傳入,服務器那裏會自動用傳入的值替換前面的"?"。須要提醒的是,傳入的參數個數必定要和SQL中的佔位符的數量同樣。

1.3 讀取記錄

熟悉ADO的朋友必定知道里面有一個DataReader對象,DBI中讀取數據的方法和它很是的類似。簡單來講,就是單向、流式的讀取數據,也就是每次只能向後讀一條數據直到沒有數據能夠讀取。

文章開頭的例子中,用了 $sth->fetchrow_array() 方法來讀取數據。其實DBI讀取數據還有幾種常見的方法,這幾個方法是相似的,所不一樣的是返回記錄的形式。

1.3.1 fetchrow_array

返回一個由字段的值組成的數組。該數組的第1個元素就是當前記錄第1個字段的值。

while ( my @row = $sth->fetchrow_array() )  {
    print "$row[0], $row[1], $row[2]\n";
}

或者這樣,不過要注意字段對應的順序

while ( my ($id, $name, $time) = $sth->fetchrow_array() )  {
    print "$id, $name, $time\n";
}

1.3.2 fetchrow_arrayref

返回由字段的值組成的數組的引用。同fetchrow_array的區別很明顯,fetchrow_arrayref返回的數組的引用。

while ( my $row_ref = $sth->fetchrow_arrayref() ) {
    for (my $i = 0; $i < @{$row_ref}; $i++)       {
        print "$row_ref->[$i]\t";
    }
    print "\n";
}

這裏要注意的是,若是要取字段的個數,須要把這個引用轉成數組的形式得到@{$row_ref} 。獲取數組元素的值的時候,由於$row_ref是引用,所以須要使用->操做符。

1.3.3 fetchrow_hashref

返回一個由」字段名-字段值」這樣的」鍵-值」對組成的HASH表。關鍵的不一樣就是,只有這個方法能夠經過一個字段名得到它的值,而沒必要關心這個字段是第幾個字段。而前者只能依靠索引來訪問值。不過缺點就是,效率要比前面兩個差一些。

while ( my $record = $sth->fetchrow_hashref() ) {
    for my $field( keys %{$record} ) {
        print "$field: $record->{$field}\t";
    }
    print "\n";
}

這裏須要複習一下HASH表的操做方法。keys操做符獲取HASH的鍵(key)的數組,$record->{$field}得到HASH表中$field對應的值。注意這裏一樣是引用,所以要用->操做符。

使用上面三個方法能夠基本解決問題了。此外,還有兩個方法fetchall_arrayrefselectall_arrayref能夠直接經過SQL一次性獲取整個數據集,不過使用上稍微複雜一些,要涉及到 perl的scalar 操做符,這裏就不贅述了。有興趣的讀者能夠參考DBI的相關資料。

最後是收尾工做。

1.4 結束一個SQL會話

$sth->finish();

1.5 斷開數據庫鏈接

$dbh->disconnect();

很簡單明瞭,就不贅述了。

Perl中利用DBI訪問數據庫的接口基本上就是這些了,還有一些高級的內容留給有興趣的讀者本身發掘研究了。可能有些讀者會感受沒有ADO、ADO.NET操做起來方便,可是在腳本的環境下可以如此方便的操做數據庫,比起用C接口來講已經方便不少了。也許在看完這片文章以後的不久,能夠在cpan上發現你的Module和全世界的Perl程序員一塊兒分享呢。

2 參考資源

相關文章
相關標籤/搜索