网络数据库教程-第4日
| 一 网络数据库教程
- 第四天 二 ePerl - Perl和HTML的结合 三 DBI - Perl的数据库接口 四 前景 ... |
嵌入式网络编程理念
几年前,网络编程起始于公共网关接口(Common Gateway Interface)简称CGI。CGI的基本概念如下:
标准的简单C程序如下:
#include <stdio.h>
int main () {
print("Hello, world!\n");
}
我可以很容易地将其转化成CGI程序,只需加入一个HTTP头。
#include <stdio.h>
int main () {
print("Content-type: text/plain\n\n");
print("Hello, world!\n");
}
下面所需作的只是编译代码,将编译后的二进制文件放在我的网络目录中适当的位置。
CGI在互联网世界的应用很广泛,但是对它也有很多不满意之处。
编写互联网应用程序最现代的方法产生于最近的几年。这些编程方法起源于基于用户端的HTML,或者叫.shtml,其概念强大之处在于将编程代码嵌入HTML文件。一些比较流行的例子如下:
本文中我不具体谈这些工具,但我打算谈一下Ralf Engelschall的ePerl,这种应用程序使你能将Perl源代码嵌入到文本文件中。它还集成了mod_perl/Apache,这些事项以前我们需要在Apache的设置中完成。mod_perl/Apache的集成强调速度及解决CGI编程中对服务器-内程序访问的失败,而ePerl则处理标准编程语言在生成HTML时的臃肿和罗嗦。
要想熟练运用ePerl,你必须对HTML和Perl都很了解。
如果你对其不了解,我们先以一个简单的HTML为例。
<HTML>
<HEAD><TITLE>A simple HTML document</TITLE></HEAD>
<BODY>
<P>
This is about as simple as it gets. No big deal.
</BODY>
</HTML>
现在我们嵌入一些Perl代码:
<HTML>
<HEAD><TITLE>A slightly less simple ePerl-HTML
document</TITLE></HEAD>
<BODY>
<P>
Just before a chunk of embedded Perl ...
<HR>
<?
my $index;
foreach $index ( 1 .. 10 ) {
print "Currently on loop index: $index\n";
}
!>
<HR>
<P>
... and now, we're just after the ePerl.
</BODY>
</HTML>
其显示结果是显而易见的。我在这里用了一个简单的"for" 循环来输出一个信息显示循环的进程。ePerl 用分割符<?开始,用分割符!>结束。在一个ePerl程序块中你仍然可以用普通的Perl输出屏幕信息。只要你了解Perl,ePerl对你来说就不难。
用ePerl进行网络编程时的注意事项:
在深入介绍ePerl之前,我还要谈一下和perl/Apache有关的两点:
mod_perl是将Perl连接到Apache网络服务器的Perl的翻译器。任何mod_perl运行的Perl程序实际上不是它们自己的程序,它们被看作是一个主程序的子程序。这样可以加快程序的速度,但也有可能带来问题:你肯定不希望在不同的Perl脚本中的变量发生重名的“冲突”。 ePerl用严格的规则避免这类事情的发生。你必须将所有的变量都声明为my,这个关键字告诉Perl将变量放在一个专有的命名位置。
在ePerl中使用#include声明时要谨慎,否则会出现问题。看一下下面的例子,一个小ePerl文件TT>time.iphtml:
<?
print scalar localtime;
!>//
我将它包括到一个大的ePerl文件 .iphtml中:
<HTML>
<HEAD><TITLE>The Current Time</TITLE></HEAD>
<BODY>
<P>
The current time is: <B>
#include time.iphtml
</B>
</BODY>
</HTML>
(文件的扩展名.iphtml是ePerl编程文件的缩写,它代表Internally Parsed HTML)
mod_perl用了一项技巧加快Perl程序在Apache中运行的速度。这项技巧就是将编译后的Perl放在高速缓存中。Perl程序运行前需要两个步骤:解释和编译。
mod_perl能 "记忆"
解释和编译阶段的结果,所以当以后还需运行该Perl程序时,mod_perl不需要再执行程序的解释和编译过程,而直接从高速缓存中调用上次解释和编译的结果。但是如果文件time.iphtml被改变了的话,则mod_perl运行该程序时就会出错,因为它不能识别对文件的改变。
DBI是一个非常实用的Perl模块。它是Perl和SQL驱动的数据库之间的接口。它使你能执行数据库的管理功能,包括Perl programs以及从你的Perl源代码发出SQL指令。每一个数据库都有一个将通用DBI接口连接特定的数据库服务器的数据库驱动器(DataBase Driver -DBD)。这样以来,用DBI编写的Perl程序具有很好的移植性。你改变所用的数据库服务器时,只需稍微改变几条Perl代码即可。
要应用DBI的神奇功能,你只需在Perl程序开始处加入这样一行:
use DBI;
如果你按照我昨天的课程设置了mod_perl/Apache的组合,那么你实际上不需要加入这行代码。我给你提供的start-up.perl文件中为你提供了让每个Perl/ePerl程序都通过mod_perl运行的功能。
实际的DBI Perl编程有很多重复和逻辑性的内容,所以解释起来很容易。
首先,你生成一个对象作为“数据库的处理器”。改对象使你能引用所有未来可能发出的SQL查询,因为它定义了你的数据库。
$dbh = DBI->connect('DBI:mysql:test:localhost', '','')
or die $DBI::errstr;
DBI->connect所用的3个参数是$database(数据库), $username(用户名),和d $password(口令)。这里我们使用昨天建立的一个试验数据库作为例子,我们无需指定用户名和口令,你可以使用字符串量DBI:mysql:test:localhost作为你的$database参数。但是这只是在本例中。如果你用别的数据库作别的事情,你需要参考DBI和DBD文献帮助你确定新的$database字符串。
下面,编写一些SQL代码,并将其放入变量。例如,在我昨天的例子中:
$SQL = <<"EOT"; select title, released from albums
where artist="Genesis" order by released EOT
这个变量是用户端光标查询(cursor)的核心。光标查询 (cursor)是一种先进的SQL查询方法,它执行逐行查询功能。该查询功能实际上在同时全部执行,但我们的Perl查询只能一行一行地获得查询结果,所以它感觉上象是针对应用程序的光标。用户端光标查询的语句及执行代码如下:
$cursor = $dbh->prepare($SQL);
$cursor->execute;
现在我们逐行进行查询:
while ( @columns = $cursor->fetchrow ) {
print ( ( map { "[$_]" } @columns ) , "\n");
}
这行Perl代码用于打印出列序列中的每一条数据-其数值利用 $cursor-> fetchrow方法从$cursor行中提取出来。其数值用[ ]包围。很显然,我可以将任何内容放在while循环内,而不只是打印语句。
最后,实现系统资源的回收和断开连接。我们关闭光标查询和数据库处理器。
$cursor->finish;
$dbh->disconnect;
如果某个你想执行的SQ指令不是select语句,你不需要使用while ( $cursor->fetchrow ) { ... } 循环,因为你实际并不需要发布会任何信息,你不需要循环查询各行。
假如在昨天的例子中,我没有从album数据库中删除my Genesis信息,我将利用今天所学的方法将其变成一个可以应用于互联网的ePerl程序。
<?
use DBI; # 假如你没有startup.perl文件则需要假如该行代码
my $dbh = DBI->connect('DBI:mysql:test:localhost', '','')
or die $DBI::errstr;
my $SQL = <<"EOT";
select title, released
from albums
where artist = 'Genesis'
order by released
EOT
my $cursor = $dbh->prepare($SQL);
$cursor->execute;
!>//
<HTML>
<HEAD><TITLE>ePerl/DBI/HTML Integration
Example</TITLE></HEAD>
<BODY>
<P>
有关Genesis albums的数据库程序结果为 ...
<HR>
<TABLE BORDER>
<TR><TH COLSPAN=2>Albums by Genesis</TH></TR>
<TR><TH>Title</TH><TH>Release
Date</TH></TR>
<?
my @columns;
while ( @columns = $cursor->fetchrow ) {
print ( "<TR>",( map { "<TD>$_</TD>" }
@columns ) , "</TR>\n");
}
!>//
</TABLE>
<HR>
<P>
... and that's it!
</BODY>
</HTML>
<?
$cursor->finish;
$dbh->disconnect;
!>//
你可以查看该程序执行的结果。
| Albums by Genesis | |
|---|---|
| Title | Release Date |
| Selling England By The Pound | 1973-01-01 |
| Trespass | 1974-01-01 |
| A Trick of the Tale | 1976-01-01 |
| Wind & Wuthering | 1976-01-01 |
| Duke | 1980-01-01 |
| We Can't Dance | 1990-01-01 |
我们已经学习了网络数据库编程的基本知识,在第5天的课程中,我们将编写一个系统演示编写网络数据库将遇到的各种情况。
在生成该数据库之前还有一些细节问题需要研究。而且我们也不能忘记我们向数据库存取信息的基本途径:HTML表单。我将用到另外一个有用的Perl 模块,CGI.pm。