网络数据库教程-第4日

---(原作/Richard Dice)
网络数据库教程 - 第四天
ePerl - Perl和HTML的结合
DBI - Perl的数据库接口
前景 ...

一、 第四天

嵌入式网络编程理念

几年前,网络编程起始于公共网关接口(Common Gateway Interface)简称CGI。CGI的基本概念如下:

  1. 当一个用户发出一个CGI请求时,URL将加入一些信息让服务器将其按照CGI请求进行处理。URL加入的信息形式可能如下:
  2. 在这些情况中,网络服务器将用户请求交给URL指定的程序进行处理,并提供相应的信息:通常是环境变量和标准输入(STDIN)。
  3. 然后程序开始运行,生成子进程并生成相应的信息,然后将其发送给标准输出(STDOUT),通常程序会生成一个尽可能简短的HTTP头信息,作为其输出的一部分。
  4. 网络服务器将“捕捉”到的捕捉输出流发通过网络送给用户。用户的浏览器根据HTTP头将其进行翻译,其结果通常是HTML文本,但是CGI程序也可以很容易地生成字节流最后将其还原为JPEG图象或RealAudio节目。

标准的简单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 - Perl和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的数据库接口

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