在本文中,我們將學(xué)習(xí)如何編寫(xiě)簡(jiǎn)單的 Perl 程序來(lái)提取或操作 IBM® DB2® Universal Database™(DB2 UDB)中存儲(chǔ)的數(shù)據(jù)。我們將從一個(gè)簡(jiǎn)單的任務(wù)入手:從數(shù)據(jù)庫(kù)中選擇一行數(shù)據(jù)放入一個(gè) Perl 程序中;接著逐步介紹一些高級(jí)主題,包括處理大對(duì)象和調(diào)用存儲(chǔ)過(guò)程。
簡(jiǎn)介
Perl(Practical Extraction and Report Language)是一種功能強(qiáng)大而又非常簡(jiǎn)單易用的編程語(yǔ)言,在很多操作系統(tǒng)上都可以使用。Perl 是免費(fèi)的。我們可以(以源代碼或二進(jìn)制的格式)下載這個(gè)語(yǔ)言,并可以免費(fèi)地使用它。
Perl 日漸成為一種廣受歡迎的語(yǔ)言。它包含了 C 編程語(yǔ)言的特性,以及 UNIX® 中的一些命令,例如 awk
和 sed
。Perl 是一種解釋語(yǔ)言,可以在單獨(dú)的應(yīng)用程序中使用,也可以與 Apache 一起來(lái)構(gòu)建 Web 應(yīng)用程序。
我們可以使用 Perl 快速操作來(lái)自文件或 RDBMS 的大型數(shù)據(jù)集。DBI 是在 Perl 腳本中連接 RDBMS 的標(biāo)準(zhǔn),它是在 1994 年開(kāi)始引入的。在 http://dbi.perl.org/ 站點(diǎn)上可以找到 DBI 驅(qū)動(dòng)程序的源代碼及其文檔。
IBM 在 1992 年為 Perl 開(kāi)發(fā)了 DB2 的驅(qū)動(dòng)程序,并隨著 DBI 規(guī)范的發(fā)展周期性地對(duì)其進(jìn)行更新。這個(gè)驅(qū)動(dòng)程序的最新版本(在撰寫(xiě)本文時(shí))是 0.78。在 http://www.ibm.com/software/data/db2/perl/ 上可以找到主要的 DBD::DB2(這是 Perl 語(yǔ)言中采用的命名機(jī)制)驅(qū)動(dòng)程序信息。
本文將展示如何編寫(xiě)簡(jiǎn)單的 Perl 程序來(lái)提取或操作 DB2 UDB 中存儲(chǔ)的數(shù)據(jù)。我們將從一個(gè)簡(jiǎn)單的任務(wù)入手:從數(shù)據(jù)庫(kù)中選擇一行數(shù)據(jù)放入一個(gè) Perl 程序中;接著逐步介紹一些高級(jí)主題,包括處理大對(duì)象和調(diào)用存儲(chǔ)過(guò)程。
開(kāi)始
圖 1 展示了 Perl 環(huán)境如何與數(shù)據(jù)庫(kù)環(huán)境進(jìn)行交互:
圖 1. Perl 環(huán)境
正如可以從這個(gè)圖中看出的,Perl 程序使用了一個(gè)標(biāo)準(zhǔn)的 API 來(lái)與 DBI(Perl 的數(shù)據(jù)庫(kù)接口模塊)進(jìn)行通信。Perl DBI 模塊只能支持動(dòng)態(tài) SQL。它定義了一組方法、變量和約定來(lái)提供一個(gè)與實(shí)際使用的數(shù)據(jù)庫(kù)獨(dú)立的一致數(shù)據(jù)庫(kù)接口。DBI 為 API 提供了一個(gè)一致的接口,它可以適用于程序員想使用的任何數(shù)據(jù)庫(kù)。DBD::DB2 是一個(gè) Perl 模塊,當(dāng)與 DBI 一起使用時(shí),它就可以讓 Perl 與 DB2 UDB 進(jìn)行通信。
因此,為了運(yùn)行訪(fǎng)問(wèn) DB2 數(shù)據(jù)庫(kù)的 Perl 腳本,需要在系統(tǒng)上安裝以下組件:
- Perl 語(yǔ)言環(huán)境
- DBI 驅(qū)動(dòng)程序(可以用于任何 RDBMS)
- DBD::DB2 驅(qū)動(dòng)程序
- DB2 Runtime Client
- C 編譯器
- DB2 數(shù)據(jù)庫(kù)服務(wù)器的連接信息
在 http://www.ibm.com/software/db2/perl/ 的 Web 站點(diǎn)上可以看到所有的安裝配置指南。
連接到 DB2 數(shù)據(jù)庫(kù)上
為了讓 Perl 程序訪(fǎng)問(wèn) DB2 數(shù)據(jù)庫(kù),需要建立到數(shù)據(jù)庫(kù)的連接。為了讓 Perl 加載 DBI 模塊,需要在 Perl DB2 應(yīng)用程序中包含下面的內(nèi)容:
use DBI;
當(dāng)使用 DBI->connect
語(yǔ)句(語(yǔ)法如下)來(lái)創(chuàng)建一個(gè)數(shù)據(jù)庫(kù)句柄 時(shí),DBI 模塊會(huì)自動(dòng)加載 DBD::DB2 驅(qū)動(dòng)程序。
清單 1. 創(chuàng)建數(shù)據(jù)庫(kù)句柄
use DBI;
$dbh = DBI->connect (“dbi:DB2:dbalias", $UserId, $password);
|
其中:
$dbh |
—— 表示 connect 語(yǔ)句所返回的數(shù)據(jù)庫(kù)句柄 |
dbalias |
—— 表示分類(lèi)進(jìn) DB2 數(shù)據(jù)庫(kù)目錄中的 DB2 別名 |
$userID |
—— 表示用來(lái)連接數(shù)據(jù)庫(kù)的用戶(hù) ID |
$password |
—— 表示這個(gè)用戶(hù) ID 的密碼 |
清單 2 展示了一個(gè)簡(jiǎn)單的 Perl 程序,它建立到數(shù)據(jù)庫(kù) SAMPLE 的連接,并返回今天的日期。這個(gè)程序執(zhí)行一條動(dòng)態(tài)生成的 DB2 SQL 語(yǔ)句,從數(shù)據(jù)庫(kù)中獲取 CURRENT DATE。它使用 DBI -> bind_col 方法將數(shù)據(jù)庫(kù)中的值傳遞到一個(gè)本地變量中,稍后我們就會(huì)討論這個(gè)問(wèn)題。
清單 2. 連接到數(shù)據(jù)庫(kù)上并執(zhí)行語(yǔ)句
#!/usr/local/bin/perl -w
use DBI;
use strict;
# Open a connection
my $dbh = DBI->connect("dbi:DB2:sample", “DB2ADMIN", “db2admin“, {RaiseError => 1});
# use VALUES to retrieve value from special register
my $stmt = "Values CURRENT DATE";
my $sth = $dbh->prepare($stmt);
$sth->execute();
# associate variables with output columns...
my $col1;
$sth->bind_col(1,\$col1);
while ($sth->fetch) { print "Today is: $col1\n"; }
$sth->finish();
$dbh->disconnect();
|
錯(cuò)誤處理 —— SQLCODE 和 SQLSTATE
為了返回與某個(gè) Perl DBI 數(shù)據(jù)庫(kù)句柄或語(yǔ)句句柄相關(guān)的 SQLSTATE,可以調(diào)用 state 方法。例如,要返回與數(shù)據(jù)庫(kù)句柄 $dbhandle 相關(guān)的 SQLSTATE ,可以在應(yīng)用程序中使用下面的 Perl 語(yǔ)句:
my $sqlstate = $dbhandle->state;
為了返回與某個(gè) Perl DBI 數(shù)據(jù)庫(kù)句柄或語(yǔ)句句柄相關(guān)的 SQLCODE,可以調(diào)用 err 方法。例如,要返回與數(shù)據(jù)庫(kù)句柄 $dbhandle 相關(guān)的 SQLCODE,可以在應(yīng)用程序中使用下面的 Perl 語(yǔ)句:
my $sqlcode = $dbhandle->err;
errstr 方法返回與某個(gè) Perl DBI 數(shù)據(jù)庫(kù)句柄或語(yǔ)句句柄相關(guān)的 SQLCODE 的消息。我推薦使用這個(gè)方法,因?yàn)檫@個(gè)方法可以給出有關(guān) SQL 語(yǔ)句失敗的更多信息。
清單 3 中的例子展示了這個(gè)方法的用法:
清單 3. 返回錯(cuò)誤消息的 errstr 方法
$dbh = DBI->connect("dbi:DB2:sample",“USERID",“password") or
die “Can't connect to sample database: $DBI::errstr";
$sth = $dbh->prepare(“SQL statement“) or die "Cannot prepare: " $dbh->errstr;
$sth->>execute() or die "Cannot execute: " $sth->errstr;
|
現(xiàn)在讓我們進(jìn)一步看一下第一個(gè)實(shí)驗(yàn)。它展示了一個(gè) Perl 程序,這個(gè)程序使用作為參數(shù)傳入的用戶(hù) ID 和密碼來(lái)連接數(shù)據(jù)庫(kù) SAMPLE。當(dāng)傳遞了有效的 ID 和密碼時(shí),它會(huì)返回一條消息說(shuō)明連接成功了。下面是 lab1.pl 的代碼:
清單 4. lab1.pl
#!/usr/local/bin/perl –w
use DBI;
$db2user = $ARGV[0];
$pasw = $ARGV[1];
# Open a connection
$dbh = DBI->connect("dbi:DB2:sample", $db2user, $pasw) or
“Can't connect to sample database: $DBI::errstr";
print "Connection is successful !!\n";
|
圖 2 給出了使用有效身份驗(yàn)證和無(wú)效身份驗(yàn)證來(lái)執(zhí)行這個(gè)程序的結(jié)果:
圖 2. 執(zhí)行 lab1.pl
執(zhí)行 SQL 語(yǔ)句
下面讓我們來(lái)編寫(xiě)一個(gè)程序,在數(shù)據(jù)庫(kù) SAMPLE 中創(chuàng)建一個(gè)表 PT_ADDR_BOOK。要執(zhí)行在編寫(xiě)應(yīng)用程序時(shí)就已經(jīng)知道的 SQL 語(yǔ)句,可以使用 $dbh->do
方法。這個(gè)方法的語(yǔ)法如下所示:
my $cnt = $dbh->do(SQL statement);
其中 $cnt
是這條 SQL 語(yǔ)句所影響的行數(shù)。
使用這個(gè)方法,我們的程序創(chuàng)建了一個(gè) DB2 表,如清單 5 所示:
清單 5. 用來(lái)創(chuàng)建 DB2 表的程序
#!/usr/local/bin/perl -w
use DBI;
use DBD::DB2::Constants;
$dbh = DBI->connect("dbi:DB2:sample","","") or
die “Can't connect to sample database: $DBI::errstr";
$rcount = $dbh->do (“CREATE TABLE PT_addr_book(name char(30),
phone char(10))");
print “Returns: $rcount\n";
|
可以使用相同的 do
方法向 PT_addr_book 表中插入幾行數(shù)據(jù)。請(qǐng)注意,所插入行的值在編寫(xiě)這個(gè)程序時(shí)都是已知的,因此可以硬編碼在代碼中。
清單 6. 使用 do 方法插入幾行數(shù)據(jù)
#!/usr/local/bin/perl -w
use DBI;
use DBD::DB2::Constants;
$dbh = DBI->connect("dbi:DB2:sample","","") or
die "Can't connect to sample database: $DBI::errstr";
$rcount = $dbh-> do ("Insert into PT_ADDR_BOOK values
('Gregory Whales','9142712020'),
('Robert Moses', 2127652345')");
print "Returns: $rcount \n";
|
正如從這個(gè)例子中可以看到的,這條 SQL 語(yǔ)句會(huì)影響兩行數(shù)據(jù)。通過(guò)在 DB2 CLP 中對(duì)這個(gè)表運(yùn)行 SELECT 語(yǔ)句,可以確定有兩行數(shù)據(jù)已經(jīng)插入了這個(gè)表中。
清單 7. test_do_exs.pl
$perl test_do_exs.pl
Returns : 2
$db2 “select * from PT_ADDR_BOOK"
NAME PHONE
------------------------------ ----------
Gregory Whales 9142712020
Robert Moses 2127652345
2 record(s) selected.
|
下面讓我們從 下載 一節(jié)中實(shí)驗(yàn) 2 的練習(xí)開(kāi)始,編寫(xiě)并執(zhí)行一個(gè)簡(jiǎn)單的 Perl 程序來(lái)更新 PR_ADDR_BOOK 表。
INSERT、UPDATE 和 DELETE 語(yǔ)句 —— 沒(méi)有占位符
執(zhí)行一條在編寫(xiě)應(yīng)用程序時(shí)還未確定的 SQL 語(yǔ)句(動(dòng)態(tài) SQL)需要使用一種不同的技術(shù),可以使用 $dbh->prepare
方法來(lái)實(shí)現(xiàn)。動(dòng)態(tài) SQL 可以通過(guò)在程序執(zhí)行過(guò)程中自己修改列、表和謂詞(操作)的能力來(lái)實(shí)現(xiàn)。動(dòng)態(tài) SQL 需要由 UDB 優(yōu)化器來(lái)準(zhǔn)備 執(zhí)行,目的是為這條語(yǔ)句創(chuàng)建一個(gè)訪(fǎng)問(wèn)計(jì)劃。如果動(dòng)態(tài) SQL 沒(méi)有參數(shù)標(biāo)記(占位符),它就可以在這個(gè)步驟之后立即執(zhí)行。清單 8 給出了 $dbh->prepare
和 $sth->execute
方法的語(yǔ)法,可以在 Perl 程序中用來(lái)執(zhí)行沒(méi)有占位符的嵌入式 SQL 語(yǔ)句:
清單 8. 動(dòng)態(tài) SQL 的準(zhǔn)備和執(zhí)行
$stmt = “SQL Statement without placeholder“;
$sth = $dbh->prepare($stmt);
$sth->execute();
|
請(qǐng)注意,$dbh->prepare
方法的結(jié)果是 SQL 語(yǔ)句句柄。
清單 9 中給出的 Perl 程序展示了如何使用這些方法將一行數(shù)據(jù)插入到 PT_ADDR_BOOK 表中:
清單 9. 插入一行數(shù)據(jù)
#!/usr/local/bin/perl -w
use DBI;
use DBD::DB2::Constants;
$dbh = DBI->connect("dbi:DB2:sample","","") or
die “Can't connect to sample database: $DBI::errstr";
$stmt = "INSERT INTO PT_addr_book values ('JOHN SMITH','9145556677')“;
$sth = $dbh->prepare($stmt);
$sth->execute();
print "We inserted row into addr_book\n";
$sth->finish();
|
具有參數(shù)標(biāo)記的 SQL 語(yǔ)句
現(xiàn)在讓我們來(lái)看一下如何執(zhí)行在編寫(xiě)應(yīng)用程序時(shí)還不確定并且具有參數(shù)標(biāo)記(即占位符)的 SQL 語(yǔ)句 —— 即真正的動(dòng)態(tài) SQL 語(yǔ)句。請(qǐng)注意,我們推薦使用這種 SQL 語(yǔ)句,因?yàn)樗鼈兙哂行阅芎桶踩苑矫娴膬?yōu)點(diǎn)。從性能的角度來(lái)看,動(dòng)態(tài) SQL 語(yǔ)句只需要準(zhǔn)備一次就可以執(zhí)行多次,可以重用相同的數(shù)據(jù)庫(kù)訪(fǎng)問(wèn)計(jì)劃。從安全性的角度來(lái)看,占位符可以確保只有一個(gè)值可以插入到這條語(yǔ)句中,從而可以避免出現(xiàn) SQL 語(yǔ)句錯(cuò)誤。
為了讓 Perl 程序?qū)?dòng)態(tài) SQL 語(yǔ)句轉(zhuǎn)換成可執(zhí)行的格式,需要首先使用 prepare 方法,然后使用 bind_param 方法來(lái)綁定參數(shù)。只有這樣才可以執(zhí)行這條語(yǔ)句。要綁定每個(gè)參數(shù),需要指定參數(shù)標(biāo)記的個(gè)數(shù),以及包含這些參數(shù)標(biāo)記值的本地 Perl 變量的名字。清單 10 給出了讓 Perl 程序執(zhí)行動(dòng)態(tài) SQL 語(yǔ)句所使用的方法的語(yǔ)法:
清單 10. 動(dòng)態(tài) SQL 的方法
$stmt = “SQL Statement with parameter marker“;
$sth = $dbh->prepare($stmt);
$sth->bind_param(1,$parm,\% attr);
$sth->execute();
|
清單 11 展示了對(duì)表 PT_ADDR_BOOK 執(zhí)行 INSERT 操作的方法。現(xiàn)在,所插入列的值不再是在 SQL 語(yǔ)句中硬編碼的了,而是使用參數(shù)標(biāo)記動(dòng)態(tài)傳遞給這條語(yǔ)句的;這些參數(shù)標(biāo)記已經(jīng)使用 $sth->bind_param 方法與這條語(yǔ)句進(jìn)行了綁定。只有完成這些設(shè)置之后,才開(kāi)始執(zhí)行這條語(yǔ)句。
清單 11. 對(duì)表 PT_ADDR_BOOK 執(zhí)行 INSERT 操作
#!/usr/local/bin/perl -w
use DBI;
use DBD::DB2::Constants;
$dbh = DBI->connect("dbi:DB2:sample","","") or
die “Can't connect to sample database :DBI::errstr";
$name ="STEVE BROWN";
$phone = "7184358769";
$stmt = "INSERT INTO PT_addr_book values (?,?)";
$sth = $dbh->prepare($stmt);
$sth->bind_param(1,$name);
$sth->bind_param(2,$phone);
$sth->execute();
print "We inserted row into addr_book\n";
$sth->finish();
|
從數(shù)據(jù)庫(kù)中檢索數(shù)據(jù) —— 單個(gè)結(jié)果
為了將數(shù)據(jù)庫(kù)中的值放到 Perl 程序中使用,需要按照下面的步驟執(zhí)行:
- 準(zhǔn)備 SELECT 語(yǔ)句。
- 執(zhí)行所準(zhǔn)備的語(yǔ)句。
- 使用 $sth->bind_col 方法把某列的值(或函數(shù))關(guān)聯(lián)到一個(gè)本地 Perl 變量上。
- 使用 $sth->fetch 方法將一個(gè)值取到本地變量中。
下面的偽碼展示了如何從數(shù)據(jù)庫(kù)中檢索單個(gè)值:
清單 12. 從數(shù)據(jù)庫(kù)中檢索單個(gè)值
$stmt = “SQL SELECT Statement to be executed“;
$sth = $dbh->prepare($stmt);
$sth->execute();
$result = $sth->bind_col(col, \variable [, \%attr ]);
while ($sth->fetch){
process result of the fetch;
}
|
下面這個(gè)例子展示了如何為一個(gè)聚合函數(shù) max
從 EMPLOYEE 表中檢索 salary 的值:
清單 13. 為聚合函數(shù)檢索值
#!/usr/local/bin/perl -w
use DBI;
use DBD::DB2::Constants;
$dbh = DBI->connect("dbi:DB2:sample","","") or
die “Can't connect to sample database: $DBI::errstr";
$stmt = "SELECT max(salary) from EMPLOYEE";
$sth = $dbh->prepare($stmt);
$sth->execute();
#associate variable with output columns...
$sth->bind_col(1,\$max_sal);
while ($sth->fetch) {
print "The biggest salary is: $max_sal\n";
}
|
下面是執(zhí)行這個(gè) Perl 程序后的結(jié)果:
清單 14. 聚合結(jié)果值
$perl test_return_value.pl
The biggest salary is: 52750.00
|
從數(shù)據(jù)庫(kù)中檢索數(shù)據(jù) —— 多個(gè)結(jié)果
從數(shù)據(jù)庫(kù)中返回一個(gè)結(jié)果集(即多個(gè)結(jié)果)到 Perl 程序中的技術(shù)與前面所采用的技術(shù)非常類(lèi)似。在準(zhǔn)備并執(zhí)行返回多個(gè)結(jié)果的 SQL 語(yǔ)句并將返回值(列)綁定到本地變量上之后,可能需要使用 $sth->fetch
方法來(lái)檢索這些值。為了展示這個(gè)方法是如何工作的,下面讓我們從 PT_ADDR_BOOK 表中檢索出 phone 和 name 列的內(nèi)容。清單 15 給出了使用一個(gè)循環(huán)來(lái)使用 $sth_fetch
方法的用法:
清單 15. 從數(shù)據(jù)庫(kù)中檢索多個(gè)值
$stmt = "SELECT name, phone from PT_ADDR_BOOK";
$sth = $dbh->prepare($stmt);
$sth->execute();
#associate variables with output columns...
$sth->bind_col(1,\$name);
$sth->bind_col(2,\$phone);
print "NAME PHONE \n";
print "------------------------- -----------\n";
while ($sth->fetch) {
print $name ;
print $phone; print "\n"; }
print "DONE \n";
$sth->finish();
|
執(zhí)行這段代碼的結(jié)果如下:
清單 16. 從數(shù)據(jù)庫(kù)中檢索多個(gè)值
C:\Dev_POT\PERL\Labs>perl multi.pl
NAME PHONE
------------------------- -----------
JOHN SMITH 9145556677
STEVE BROWN 7184358769
DONE
|
也可以使用 $sth->fetchrow
方法從結(jié)果集中檢索數(shù)據(jù)。$sth ->fetch
方法會(huì)將每個(gè)值作為單獨(dú)一項(xiàng)返回,而 $sth ->fetchrow()
方法則將一行作為一個(gè)數(shù)組返回,每列的值都是該數(shù)組中的一個(gè)元素。
可以使用 fetchrow
方法編寫(xiě)功能相同的 Perl 程序,如下所示:
清單 17. 從數(shù)據(jù)庫(kù)中檢索多個(gè)值
$stmt = "SELECT name, phone from PT_ADDR_BOOK";
$sth = $dbh->prepare($stmt);
$sth->execute();
print "NAME PHONE \n";
print "------------------------- -----------\n";
while (($name, $phone) = $sth->fetchrow())
{ print "$name $phone\n"; }
|
我們可以從 實(shí)驗(yàn) 3 開(kāi)始編寫(xiě)并執(zhí)行一個(gè) Perl 程序,它可以創(chuàng)建一個(gè) DB2 表,向該表中插入一些數(shù)據(jù),并返回插入該表中的行數(shù)。
調(diào)用存儲(chǔ)過(guò)程
下面讓我們來(lái)創(chuàng)建一個(gè)多個(gè)步驟的場(chǎng)景,從而詳細(xì)了解一下如何從 Perl 程序中調(diào)用 DB2 的存儲(chǔ)過(guò)程。首先,創(chuàng)建一個(gè)簡(jiǎn)單的存儲(chǔ)過(guò)程 SP_GET_LOC,它從表 ORG 中返回某個(gè)給定部門(mén)的位置(步驟 1)。
清單 18. 步驟 1:創(chuàng)建存儲(chǔ)過(guò)程
create procedure sp_get_loc (in deptin int, out loc varchar(13))
begin
select location into loc from org where deptnumb = deptin;
end @
|
請(qǐng)注意,這個(gè)存儲(chǔ)過(guò)程有一個(gè)輸入?yún)?shù)和一個(gè)輸出參數(shù)。當(dāng)我們?cè)?DB2 的命令行處理器(CLP)中運(yùn)行這個(gè)過(guò)程時(shí),它對(duì)部門(mén) 10 會(huì)返回位置 NEW YORK。
清單 19. 步驟 2:運(yùn)行存儲(chǔ)過(guò)程
$db2 "call sp_get_loc(10,?)"
Value of output parameters
--------------------------
Parameter Name : LOC
Parameter Value : New York
Return Status = 0
|
下面讓我們來(lái)編寫(xiě)一個(gè)簡(jiǎn)單的 Perl 程序來(lái)調(diào)用存儲(chǔ)過(guò)程 SP_GET_LOC(步驟 3,請(qǐng)參看 清單 20)。我們的動(dòng)態(tài) SQL 語(yǔ)句實(shí)際上與在 DB2 CLP 中執(zhí)行的語(yǔ)句相同,形式為 SP_GET_LOC(?,?)
,不過(guò)在 CLP 中是傳遞硬編碼的 10(部門(mén)編號(hào)),在動(dòng)態(tài) SQL 語(yǔ)句中將使用一個(gè)參數(shù)標(biāo)記。采用這種方法,就可以對(duì) ORG 表的部門(mén)編號(hào)列的任何值查詢(xún)位置了。
在構(gòu)造 SQL 語(yǔ)句之后,剩下的步驟就與其他具有參數(shù)標(biāo)記的動(dòng)態(tài)語(yǔ)句完全相同了。可以使用 $sth = $dbh->prepare
方法進(jìn)行準(zhǔn)備。使用 $sth->bind_param
方法將部門(mén)編號(hào)綁定為輸入?yún)?shù),使用 $sth->bind_param_inout
方法將返回的位置綁定為輸出參數(shù),然后再執(zhí)行動(dòng)態(tài) SQL 語(yǔ)句。
該程序如下:
清單 20. 步驟 3:調(diào)用存儲(chǔ)過(guò)程
#!/usr/bin/perl -w
use DBI;
use DBD::DB2::Constants;
$dbh = DBI->connect("dbi:DB2:sample","","") or
die "Can't connect to sample database: $DBI::errstr";
# Prepare our call statement
$sth = $dbh->prepare( "CALL SP_GET_LOC(?,?)" );
# Bind input parameter for department number
$sth->bind_param(1, 10);
# Bind output parameter - location
$sth->bind_param_inout (2, \$location, 13, db2_param_type=>SQL_PARAM_OUTPUT});
# Call the stored procedure
$sth->execute();
printf("Stored procedure returned location: %s\n", $location);
$sth->finish();
$dbh->disconnect;
|
如果執(zhí)行這個(gè)程序,就會(huì)看到給定部門(mén)(本例中為 10)的 LOCATION:
清單 21. 步驟 4:執(zhí)行調(diào)用 DB2 存儲(chǔ)過(guò)程的 Perl 程序
$perl test_call_sp.pl
Stored Procedure returned location: New York
|
大對(duì)象的操作
使用 Perl 來(lái)處理文件比使用其他更復(fù)雜的語(yǔ)言(例如 C 或 Java®)都要簡(jiǎn)單。下面我們就會(huì)看到如何將數(shù)據(jù)直接從文件中導(dǎo)入 DB2 的大對(duì)象數(shù)據(jù)(LOB)列中。插入大對(duì)象數(shù)據(jù)的最有效的方法是,將這個(gè)文件直接綁定到 DB2 表中一個(gè)與 LOB 類(lèi)型的列相關(guān)聯(lián)的輸入?yún)?shù)上。Perl 驅(qū)動(dòng)程序可以直接從文件中讀取數(shù)據(jù),并將數(shù)據(jù)傳遞給數(shù)據(jù)庫(kù)服務(wù)器。要將一個(gè)文件綁定到某個(gè)輸入 LOB 參數(shù)上,可以在執(zhí)行 INSERT 操作過(guò)程中使用 bind_param
方法來(lái)指定 { db2_file => 1} 參數(shù)屬性。
在我們的數(shù)據(jù)庫(kù)模式 POT 下面有一個(gè)表 MAP。這個(gè)表有一個(gè) picture 列,它被聲明成 BLOB 類(lèi)型的,用來(lái)存放某個(gè)地區(qū)的圖像。下面是創(chuàng)建該表所使用的 DDL:
清單 22. 創(chuàng)建 MAP 表使用的 DDL
create table POT.MAPS
( map_id INT,
map_name VARCHAR(13),
area INT ,
photo_format CHAR(3),
picture BLOB) ;
|
另外,我們還有一個(gè)文件 pearcson.jpg,其中包含了 Pearson Airport 的地圖。
圖 3. 示例地圖
現(xiàn)在讓我們來(lái)編寫(xiě)一個(gè)程序,向表 POT.MAP 中插入一行數(shù)據(jù),即將 JPG 文件的圖像插入到 PICTURE 中。首先,需要構(gòu)造一個(gè)具有 5 個(gè)參數(shù)標(biāo)記的動(dòng)態(tài) SQL 語(yǔ)句。然后,需要對(duì)這條語(yǔ)句進(jìn)行準(zhǔn)備。在將參數(shù)綁定到準(zhǔn)備好的語(yǔ)句上之前,需要指定包含要插入的圖像的文件名,并將其賦給一個(gè)本地 Perl 變量($picture_file
)。現(xiàn)在可以將所有參數(shù)全部綁定到需要插入到 MAP 表中的值上。請(qǐng)注意,我們?yōu)樽詈笠粋€(gè)參數(shù)指定了 db2_file =>1
屬性。最后一個(gè)步驟是執(zhí)行這條 INSERT 語(yǔ)句。這個(gè)程序的代碼如下:
清單 23. 插入 LOB
#!/usr/bin/perl -w
use DBI;
use DBD::DB2::Constants;
%conattr = ( AutoCommit => 1,
# Turn Autocommit On
db2_info_applname => 'Maps Module', );
# Identify this appl
$dbh = DBI->connect("dbi:DB2:sample","", "",\%conattr) or die "$DBI::errstr";
$dbh->do("SET CURRENT SCHEMA POT");
$sql = "INSERT INTO MAPS(map_id, map_name, area, photo_format, picture)
VALUES(?,?,?,?,?)";
$sth = $dbh->prepare($sql);
$picture_file = "pearson.jpg"; # File containing our picture
$sth->bind_param(1, 100); # map_id
$sth->bind_param(2, "Pearson airport"); # map_name
$sth->bind_param(3, 416); # area
$sth->bind_param(4, "JPG"); # photo_format
$sth->bind_param(5, $picture_file, {db2_file => 1});
$rows_affected = $sth->execute();
printf("%d rows affected", $rows_affected);
$sth->finish();
$dbh->disconnect;
|
從數(shù)據(jù)庫(kù)中讀取 LOB 數(shù)據(jù)
可以使用標(biāo)準(zhǔn)的 fetch 方法來(lái)檢索 LOB 數(shù)據(jù),例如 fetchrow_array
或 fetchrow_arrayref
。DBI 讓我們可以使用 LongReadLen
連接屬性來(lái)設(shè)置每次 fetch 可以檢索的最大字節(jié)數(shù)。對(duì)于 LOB 列來(lái)說(shuō),缺省值為 32,700 個(gè)字節(jié)。要實(shí)現(xiàn)這種功能,需要執(zhí)行以下步驟:
- 構(gòu)造 SQL 語(yǔ)句從 MAP 表中選擇 picture 列的數(shù)據(jù)。
- 準(zhǔn)備 SQL 語(yǔ)句。
- 為保存所檢索到的圖像使用的文件分配一個(gè)名字。
- 打開(kāi)該文件。
- 執(zhí)行這條 SQL 語(yǔ)句。
- 使用 fetch 方法將結(jié)果取到文件中。
下面是展示如何從數(shù)據(jù)庫(kù)中檢索 LOB 數(shù)據(jù)的代碼:
清單 24. 從數(shù)據(jù)庫(kù)中讀取 LOB 數(shù)據(jù)
#!/usr/bin/perl
use DBI;
use DBD::DB2::Constants;
%conattr =
(
AutoCommit => 1,
# Turn Autocommit On
db2_info_applname => 'Maps Module',
# Identify this appl
LongReadLen => 80000
# Don't retrieve LOBs
);
# Connect to our database
$dbh = DBI->connect("dbi:DB2:sample","", "",\%conattr) or
die "$DBI::errstr";
# Set the current schema to 'POT'
$dbh->do("SET CURRENT SCHEMA POT");
$sql = "SELECT picture FROM maps WHERE map_name ='Pearson airport'";
# Prepare the statement
$sth = $dbh->prepare($sql);
# Open output file
$out_file = "mypic.jpg";
open(OUTPUT, ">$out_file") or die "Cannot open $out_file because $!";
binmode OUTPUT;
$sth->execute;
@row = $sth->fetchrow;
print OUTPUT $row[0];
@row = "";
close(OUTPUT);
print “Picture in the file $out_file\n";
$sth->finish();
$dbh->disconnect;
|
在運(yùn)行這個(gè)程序之后,圖像就保存到 mypic.jpg 文件中了。
清單 25. 從數(shù)據(jù)庫(kù)中讀取 LOB 數(shù)據(jù)
$perl test_lobread.pl
Picture in the file mypic.jpg
|
請(qǐng)使用 實(shí)驗(yàn) 4 中的練習(xí)來(lái)編寫(xiě)并執(zhí)行一個(gè) Perl 程序,它從一個(gè)表中檢索出二進(jìn)制大對(duì)象,并將其保存到一個(gè)文件中。
結(jié)束語(yǔ)
本文是為那些具有關(guān)系數(shù)據(jù)庫(kù)經(jīng)驗(yàn)并且希望學(xué)習(xí)如何編寫(xiě) Perl 程序來(lái)訪(fǎng)問(wèn) DB2 數(shù)據(jù)庫(kù)的 Perl 程序員編寫(xiě)的。在本文中,我們已經(jīng)學(xué)習(xí)了如何連接數(shù)據(jù)庫(kù),如何通過(guò) INSERT、UPDATE 和 DELETE 語(yǔ)句來(lái)操作數(shù)據(jù)庫(kù)的內(nèi)容。還學(xué)習(xí)了如何從數(shù)據(jù)庫(kù)中檢索數(shù)據(jù),并介紹了一些高級(jí)主題,包括調(diào)用存儲(chǔ)過(guò)程和操作大數(shù)據(jù)對(duì)象(LOB 和 BLOB)。現(xiàn)在我們應(yīng)該已經(jīng)準(zhǔn)備好使用自己剛掌握的 Perl DB2 編程技巧來(lái)開(kāi)發(fā)自己的程序了。
原文鏈接:http://www-128.ibm.com/developerworks/cn/db2/library/techarticles/dm-0512greenstein/index.html