5

背景

下面是一段典型的 Perl 代码(用于讨论的sample.pl),它使用 CGI 抓取提交的表单数据,将表单数据传递给 DBI,然后 DBI 从 MySQL 检索所需的行,然后将结果传递给 Template Toolkit呈现为 HTML 文档以供显示。

sample.pl的代码清单:

#!/usr/bin/perl
use strict;
use CGI;
use DBI:
use Template;

#Grab submitted form data
my $cgi = CGI->new();
my $idFromSomewhere= $cgi->param('id');

my $driver   = "mysql";
my $server   = "localhost:3306";
my $database = "test";
my $url      = "DBI:$driver:$database:$server";
my $user     = "apache";
my $password = "";

#Connect to database
my $db_handle = DBI->connect( $url, $user, $password ) 
    or die $DBI::errstr;

#SQL query to execute
my $sql = "SELECT * FROM tests WHERE id=?";

#Prepare SQL query
my $statement = $db_handle->prepare($sql)
        or die "Couldn't prepare query '$sql': $DBI::errstr\n";

#Execute SQL Query
$statement->execute($idFromSomewhere)
    or die "Couldn't execute query '$sql': $DBI::errstr\n";

#Get query results as hash
my $results = $statement->fetchall_hashref('id');

$db_handle->disconnect();
my $tt = Template->new();

#HTML output template
my $input = 'template.html';
my $vars = {
    tests => $results,
};

#Process template and output as HTML
$tt->process($input, $vars)
    or die $tt->error();

为了获得更好的性能和可扩展性,提供共享服务器的 Web 主机(例如 Dreamhost)强烈建议所有生产 Perl 脚本都支持 FastCGI。FastCGI 文档非常清楚如何修改现有的 Perl 代码以支持 FastCGI。下面的简单代码通常作为示例给出:

use FCGI;
while (FCGI::accept >= 0)
{    
   #Run existing code.
}

不太清楚的是在 while 循环中放置的位置和内容。

子问题

A. sample.pl 中的代码是否应该像这样简单地包裹现有代码:

while (FCGI::accept >= 0)
{    
    #Grab submitted form data
    my $cgi = CGI->new();
    ...
    ...
    #Process template and output as HTML
    $tt->process($input, $vars)
    or die $tt->error();
}

B. 或者还有更多内容?例如,处理 cgi、数据库和模板的代码是否应该重构为它们自己的子程序?

C. DBI->connect() 和 $db_handle->disconnect() 应该在 FCGI while 循环内部还是外部调用?对性能有何影响?

D. 应该在 FCGI while 循环内部还是外部调用 $tt->process()?

4

3 回答 3

10

如果您熟悉 CGI.pm,则使用 FCGI.pm 没有意义,请使用 CGI::Fast。

您的示例转换为使用 CGI::Fast 将是:

#!/usr/bin/perl
use strict;
use CGI::Fast;
use DBI;
use Template;

my $driver   = "mysql";
my $server   = "localhost:3306";
my $database = "test";
my $url      = "DBI:$driver:$database:$server";
my $user     = "apache";
my $password = "";

#Connect to database
my $db_handle = DBI->connect( $url, $user, $password ) or die $DBI::errstr;

while ( my $cgi = CGI::Fast->new() ) {

    #Grab submitted form data
    my $idFromSomewhere = $cgi->param( 'id' );

    #SQL query to execute
    my $sql = "SELECT * FROM tests WHERE id=?";

    #Prepare SQL query
    my $statement = $db_handle->prepare( $sql )
        or die "Couldn't prepare query '$sql': $DBI::errstr\n";

    #Execute SQL Query
    $statement->execute( $idFromSomewhere )
        or die "Couldn't execute query '$sql': $DBI::errstr\n";

    #Get query results as hash
    my $results = $statement->fetchall_hashref( 'id' );

    my $tt = Template->new();

    #HTML output template
    my $input = 'template.html';
    my $vars = { tests => $results, };

    #Process template and output as HTML
    $tt->process( $input, $vars )
        or die $tt->error();
}

至于你的子问题:

  • 答:除非您 100% 确定自己知道自己在做什么,否则不要使用 FCGI。你肯定想要 CGI::Fast :)
  • B:我会重构它以提高可读性
  • C:如果您在接受连接之前使用 DBI->connect,您将获得永久的数据库连接,这从性能的角度来看非常棒
  • D:肯定在里面。

顺便说一句——如果你想用 Perl 开发网站,至少看看 Catalyst ( http://www.catalystframework.org/ )

于 2009-06-04T09:43:48.970 回答
1

如果您想使用 FCGI,则只需在该循环中执行最低限度的操作即可启动任务。其他一切都应该存在于模块中,您需要做的就是传递输入。

use FCGI;
while (FCGI::accept >= 0)
    {    
    MyApplication->activate( @args );
    }

其余的东西在 MyApplication 的某个地方。任何有趣的东西都不应该出现在 FastCGI 脚本中。您不需要将所有应用程序的东西与激活它的东西紧密结合起来。

你可能想看看我在Mastering Perl中关于 modulinos 的章节,看看如何将你的脚本变成可重用的模块。这样的事情让这样的事情变得非常容易。

对于持久性数据库连接,您还有一些工作要做。您可以在循环外启动连接,但您需要定期 ping 它并可能重新建立它。看看Apache::DBI是什么。

于 2009-06-04T21:56:16.180 回答
0

子问题 C:(持久的数据库连接)

看看DBI->connect_cached()。我相信你可以你的 CGI::Fast 循环中使用它,并且 DBI.pm 会记住/缓存你的连接。因此,在第 2 次、第 3 次等使用相同参数调用 connect_cached() 时,您将取回现有连接。如果旧连接不再可用,它将创建一个新连接。

这种方法真正好的地方在于,您必须对现有应用程序进行的唯一更改(除了添加 CGI::Fast 循环)是将 connect() 替换为 connect_cached()。并且 connect_cached() 也可以与普通的 CGI 一起使用。

另请参阅我是否必须将 DB 连接/初始化放在 FCGI 循环之外才能利用 Perl 中的 FastCGI?http://www.mail-archive.com/cgiapp@lists.erlbaum.net/msg04351.html

于 2009-11-21T04:03:02.457 回答