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.
下面是使用CGI抓取提交的表单数据的典型Perl代码片段(sample.pl),将表单数据传递给DBI,DBI然后从MySQL检索所需的行,然后将结果交给Template Toolkit呈现为HTML文档以供显示。
Code listing for sample.pl :
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:
为了获得更好的性能和可伸缩性,提供共享服务器的Web主机(如Dreamhost)强烈建议所有生产的Perl脚本都支持FastCGI。 FastCGI文档非常清楚如何修改现有的Perl代码以支持FastCGI。下面的简单代码通常作为示例给出:
use FCGI;
while (FCGI::accept >= 0)
{
#Run existing code.
}
What's not so clear is where and what to put in the while loop.
什么不太清楚的是在while循环中放置的位置和内容。
Sub Questions
A. Should the code in sample.pl be simply wrapped around the existing code like so:
答: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. Or is there more to it? For instance, should the code that handles the cgi, database and template be refactored into their own subs?
B.或者还有更多吗?例如,处理cgi,数据库和模板的代码是否应该重构为自己的子代码?
C. Should DBI->connect() and $db_handle->disconnect() be called inside or outside the FCGI while loop and what are the performance implications?
C. DBI-> connect()和$ db_handle-> disconnect()是否应在循环中调用FCGI内部或外部,以及性能影响是什么?
D. Should $tt->process() be called inside or outside the FCGI while loop?
D.应该在循环期间在FCGI内部或外部调用$ tt-> process()吗?
3 个解决方案
#1
If you're familiar with CGI.pm, there is no point in using FCGI.pm, use CGI::Fast.
如果您熟悉CGI.pm,使用FCGI.pm没有意义,请使用CGI :: Fast。
Your example converted to use CGI::Fast would be:
转换为使用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();
}
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.
答:除非你100%确定你知道自己在做什么,否则不要使用FCGI。你绝对想要CGI :: Fast :)
B:为了便于阅读,我会重构它
C:如果在接受连接之前使用DBI-> connect,则会获得永久数据库连接,从性能角度来看这是很好的
D:绝对在里面。
Just as a side information - if you want to develop websites in Perl, at least take a look at Catalyst (http://www.catalystframework.org/)
就像一个辅助信息 - 如果你想在Perl中开发网站,至少看一下Catalyst(http://www.catalystframework.org/)
#2
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.
如果要使用FCGI,则只在该循环中执行最低限度以启动任务。其他所有东西都应该存在于模块中,您需要做的就是传递输入。
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.
剩下的东西都在MyApplication的某个地方。任何有趣的东西都不应该在FastCGI脚本中。你不需要将所有应用程序内容与激活它的东西紧密结合在一起。
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.
您可能希望在Mastering Perl中查看关于modulinos的章节,了解如何将脚本转换为可重用模块。这样的事情让这样的事情变得非常简单。
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.
对于持久数据库连接,您还需要做更多工作。您可以在循环外部启动连接,但是您需要定期ping它并重新建立它。看看Apache :: DBI的用途。
#3
Subquestion C: (persistent DB connections)
子问题C :(持久数据库连接)
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.
看看DBI-> connect_cached()。我相信你可以在你的CGI :: Fast循环中使用它,而DBI.pm将记住/缓存你的连接。因此,在使用相同参数调用connect_cached()的第2个,第3个等时,您将返回现有连接。如果旧连接不再可用,它将创建新连接。
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.
这种方法的真正好处在于,您必须对现有应用程序进行的唯一更改(除了添加CGI :: Fast循环之外)是将connect()替换为connect_cached()。而且connect_cached()也可以使用普通的CGI。
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/cgiapp@lists.erlbaum.net/msg04351.html
另请参阅我是否必须将数据库连接/初始化置于FCGI循环之外以利用Perl中的FastCGI?和http://www.mail-archive.com/cgiapp@lists.erlbaum.net/msg04351.html
#1
If you're familiar with CGI.pm, there is no point in using FCGI.pm, use CGI::Fast.
如果您熟悉CGI.pm,使用FCGI.pm没有意义,请使用CGI :: Fast。
Your example converted to use CGI::Fast would be:
转换为使用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();
}
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.
答:除非你100%确定你知道自己在做什么,否则不要使用FCGI。你绝对想要CGI :: Fast :)
B:为了便于阅读,我会重构它
C:如果在接受连接之前使用DBI-> connect,则会获得永久数据库连接,从性能角度来看这是很好的
D:绝对在里面。
Just as a side information - if you want to develop websites in Perl, at least take a look at Catalyst (http://www.catalystframework.org/)
就像一个辅助信息 - 如果你想在Perl中开发网站,至少看一下Catalyst(http://www.catalystframework.org/)
#2
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.
如果要使用FCGI,则只在该循环中执行最低限度以启动任务。其他所有东西都应该存在于模块中,您需要做的就是传递输入。
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.
剩下的东西都在MyApplication的某个地方。任何有趣的东西都不应该在FastCGI脚本中。你不需要将所有应用程序内容与激活它的东西紧密结合在一起。
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.
您可能希望在Mastering Perl中查看关于modulinos的章节,了解如何将脚本转换为可重用模块。这样的事情让这样的事情变得非常简单。
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.
对于持久数据库连接,您还需要做更多工作。您可以在循环外部启动连接,但是您需要定期ping它并重新建立它。看看Apache :: DBI的用途。
#3
Subquestion C: (persistent DB connections)
子问题C :(持久数据库连接)
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.
看看DBI-> connect_cached()。我相信你可以在你的CGI :: Fast循环中使用它,而DBI.pm将记住/缓存你的连接。因此,在使用相同参数调用connect_cached()的第2个,第3个等时,您将返回现有连接。如果旧连接不再可用,它将创建新连接。
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.
这种方法的真正好处在于,您必须对现有应用程序进行的唯一更改(除了添加CGI :: Fast循环之外)是将connect()替换为connect_cached()。而且connect_cached()也可以使用普通的CGI。
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/cgiapp@lists.erlbaum.net/msg04351.html
另请参阅我是否必须将数据库连接/初始化置于FCGI循环之外以利用Perl中的FastCGI?和http://www.mail-archive.com/cgiapp@lists.erlbaum.net/msg04351.html