如何重构使用 Template Toolkit 和 DBI 的 Perl 代码以利用 FastCGI?

发布于 2024-07-22 17:41:55 字数 2207 浏览 10 评论 0原文

背景

下面是一段典型的 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. 应该在 FCGI while 循环内部还是外部调用 DBI->connect() 和 $db_handle->disconnect() 以及对性能有何影响?

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

Background

Below is a typical piece of Perl code (sample.pl for the sake of discussion) that grabs submitted form data using CGI, passes the form data to DBI which will then retrieve the required rows from MySQL and then hands the results over to Template Toolkit to render into a HTML document for display.

Code listing for 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();

For better performance and scalability, web hosts providing shared servers, such as Dreamhost, strongly recommend that all production Perl script support FastCGI. The FastCGI documentation is pretty clear on how to modify existing Perl code to support FastCGI. The simple code below is often given as an example:

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

What's not so clear is where and what to put in the while loop.

Sub Questions

A.
Should the code in sample.pl be simply wrapped around the existing code like so:

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.
Or is there more to it? For instance, should the code that handles the cgi, database and template be refactored into their own subs?

C.
Should DBI->connect() and $db_handle->disconnect() be called inside or outside the FCGI while loop and what are the performance implications?

D.
Should $tt->process() be called inside or outside the FCGI while loop?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

狂之美人 2024-07-29 17:41:55

如果您熟悉 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();
}

至于您的子问题:

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

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

If you're familiar with CGI.pm, there is no point in using FCGI.pm, use CGI::Fast.

Your example converted to use CGI::Fast would be:

#!/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();
}

As for your sub questions:

  • A:
    Do not use FCGI unless you are 100% sure that you know what you're doing. You definitely want CGI::Fast :)
  • B:
    I would refactor it for readability
  • C: if you use DBI->connect before accepting connection you get permanent database connection which is great from performance standpoint
  • D: definitely inside.

Just as a side information - if you want to develop websites in Perl, at least take a look at Catalyst (http://www.catalystframework.org/)

秋意浓 2024-07-29 17:41:55

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

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

其余的东西都在 MyApplication 的某个地方。 任何有趣的内容都不应该出现在 FastCGI 脚本中。 您不知道如何将所有应用程序内容与激活它的内容紧密耦合。

你可能想看看我在 掌握 Perl 中关于 modulinos 的章节,看看如何将你的脚本变成可重复使用的模块。 诸如此类的事情让事情变得非常容易。

对于持久数据库连接,您还有更多的工作要做。 您可以在环路外启动连接,但您需要定期对其进行 ping 操作,或许还需要重新建立连接。 请参阅 Apache::DBI 来了解这一点。

If you want to use FCGI, then only do the bare minimum in that loop to start the task. Everything else should live in modules, and all you need to do is pass the input along.

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

The rest of the stuff is in MyApplication somewhere. Anything interesting shouldn't be in the FastCGI script. You don't what to tightly couple all the application stuff with the thing that's activating it.

You might want to see my chapter on modulinos in Mastering Perl to see how you can turn your scripts into re-usable modules. That sort of thing makes stuff like this really easy.

For the persistent database connections, you have a little bit more work to do. You can start a connection outside the loop, but periodicially you need to ping it and perhaps re-establish it. See what Apache::DBI for this.

年华零落成诗 2024-07-29 17:41:55

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

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

这种方法的真正好处是,您必须对现有应用程序进行的唯一更改(除了添加 CGI::Fast 循环)就是用 connect_cached() 替换 connect()。 connect_cached() 也适用于普通 CGI。

另请参阅我是否必须将数据库连接/初始化置于 FCGI 循环之外才能利用 Perl 中的 FastCGI?

http://www.mail-archive.com/[电子邮件受保护]/msg04351.html

Subquestion C: (persistent DB connections)

Take a look at DBI->connect_cached(). I believe you can use it inside your CGI::Fast loop, and DBI.pm will remember/cache your connection. So, on the 2nd, 3rd, etc. calls to connect_cached() with the same parameters, you will get back an existing connection. It will create a new connection if the old one is no longer available.

What's really nice about this approach is that the only change you have to make to your existing application (other than adding the CGI::Fast loop) is to replace connect() with connect_cached(). And connect_cached() will work with plain vanilla CGI too.

See also Do I have to put DB connection/initialization outside of the FCGI loop to take advantage of FastCGI in Perl?
and
http://www.mail-archive.com/[email protected]/msg04351.html

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文