网络数据库教程-第四天
一、 第四天
嵌入式网络编程理念
几年前,网络编程起始于公共网关接口(Common Gateway Interface)简称CGI。CGI的基本概念如下:
当一个用户发出一个CGI请求时,URL将加入一些信息让服务器将其按照CGI请求进行处理。URL加入的信息形式可能如下:
用户请求的CGI一般在/cgi-bin/ 子目录:http://www.somewhere.com/cgi-bin/某个CGI程序
网络服务器的配置可能会自动将某些文件的扩展名识别为可以执行的CGI程序:http://www.erehwon.org/gosearch.py.py 通常被理解为Python程序,这是另外一种很流行的网络编程语言。
文件的扩展名可能直接采用CGI作为扩展名:http://www.xyz.net/dosomething.cgi
在这些情况中,网络服务器将用户请求交给URL指定的程序进行处理,并提供相应的信息:通常是环境变量和标准输入(STDIN)。
然后程序开始运行,生成子进程并生成相应的信息,然后将其发送给标准输出(STDOUT),通常程序会生成一个尽可能简短的HTTP头信息,作为其输出的一部分。
网络服务器将“捕捉”到的捕捉输出流发通过网络送给用户。用户的浏览器根据HTTP头将其进行翻译,其结果通常是HTML文本,但是CGI程序也可以很容易地生成字节流最后将其还原为JPEG图象或RealAudio节目。
标准的简单C程序如下:
#include
int main () {
print(\"Hello, world!\\n\");
}
我可以很容易地将其转化成CGI程序,只需加入一个HTTP头。
#include
int main () {
print(\"Content-type: text/plain\\n\\n\");
print(\"Hello, world!\\n\");
}
下面所需作的只是编译代码,将编译后的二进制文件放在我的网络目录中适当的位置。
CGI在互联网世界的应用很广泛,但是对它也有很多不满意之处。
生成子进程是一个相当复杂的工作,耗费很多时间和内存,许多访问率相当高的站点的开发人员常因为由此造成的速度问题抱怨不已。
网络服务器包含很多信息,而不只是环境变量和标准输入(STDIN)。有时候如果网络程序能够访问这些资料将会带来许多便利。
传统的编程对于互联网来说都显得过于臃肿庞大,你最需要的其实就是一个能代替你编写HTML的一个智能程序,所以,为什么要把程序编得象计算机的代码呢?为什么不能使它更象HTML本身?
编写互联网应用程序最现代的方法产生于最近的几年。这些编程方法起源于基于用户端的HTML,或者叫.shtml,其概念强大之处在于将编程代码嵌入HTML文件。一些比较流行的例子如下:
Active Server Pages (.asp文件), 这种程序应用于微软的IIS网络服务器。ASP文件可以用几种比特的脚本编写引擎例如VBScript, JavaScript,和PerlScript启动。
Allaire Cold Fusion,这是一种非常方便的商用互联网开发环境。尽管它最初只能用于Windows NT,但后来它也开发出了适用于UNIX的版本。
Meta-HTML, 这种\"免费软件\"适用于UNIX 系统,它支持ODBC以及本地化的mSQL接口,它可以提供用于Netscape和Apache网络服务器的插件软件。
本文中我不具体谈这些工具,但我打算谈一下Ralf Engelschall的ePerl,这种应用程序使你能将Perl源代码嵌入到文本文件中。它还集成了mod_perl/Apache,这些事项以前我们需要在Apache的设置中完成。mod_perl/Apache的集成强调速度及解决CGI编程中对服务器-内程序访问的失败,而ePerl则处理标准编程语言在生成HTML时的臃肿和罗嗦。
二、ePerl - Perl和HTML的结合
要想熟练运用ePerl,你必须对HTML和Perl都很了解。
如果你对其不了解,我们先以一个简单的HTML为例。
This is about as simple as it gets. No big deal.
现在我们嵌入一些Perl代码:
Just before a chunk of embedded Perl ...
--------------------------------------------------------------------------------
my $index;
foreach $index ( 1 .. 10 ) {
print \"Currently on loop index: $index\\n\";
}
!>
--------------------------------------------------------------------------------
... and now, we\re just after the ePerl.
其显示结果是显而易见的。我在这里用了一个简单的\"for\" 循环来输出一个信息显示循环的进程。ePerl 用分割符结束。在一个ePerl程序块中你仍然可以用普通的Perl输出屏幕信息。只要你了解Perl,ePerl对你来说就不难。
用ePerl进行网络编程时的注意事项:
ePerl能自动识别你的网络文件的性质并用一个适当的HTTP头加以输出。如果你的文件是HTML,它的输出则是text/html,否则它就简单地用text/plain输出。
当需要在HTML中插入变量的数值时,ePerl可以使用快捷键,其特殊的定界序列是
在!>结尾分割符之后你可以加入//以防止输出 行。这可以避免将HTML源程序显示到网络中。
你可以用#include声明将其他文件包括到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中:
The current time is:
#include time.iphtml
(文件的扩展名.iphtml是ePerl编程文件的缩写,它代表Internally Parsed HTML)
mod_perl用了一项技巧加快Perl程序在Apache中运行的速度。这项技巧就是将编译后的Perl放在高速缓存中。Perl程序运行前需要两个步骤:解释和编译。 mod_perl能 \"记忆\" 解释和编译阶段的结果,所以当以后还需运行该Perl程序时,mod_perl不需要再执行程序的解释和编译过程,而直接从高速缓存中调用上次解释和编译的结果。但是如果文件time.iphtml被改变了的话,则mod_perl运行该程序时就会出错,因为它不能识别对文件的改变。
三、 DBI - 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;
!>//
有关Genesis albums的数据库程序结果为 ...
--------------------------------------------------------------------------------
Albums by Genesis
Title Release
Date
my @columns;
while ( @columns = $cursor->fetchrow ) {
print ( \" \",( map { \" $_ \" }
@columns ) , \"
\\n\");
}
!>//
--------------------------------------------------------------------------------
... and that\s it!
$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。发布人:Crystal 来自:LinuxAid