为什么 Apache 抱怨我的 mod_perl 程序“断开连接使 1 个活动语句句柄无效”?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/541542/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Why does Apache complain that my mod_perl program "disconnect invalidates 1 active statement handle"?
提问by GeneQ
disconnect invalidates 1 active statement handle (either destroy statement handles or call finish on them before disconnecting)
断开连接使 1 个活动语句句柄无效(在断开连接之前销毁语句句柄或调用它们)
The following code which grabs data from MySQL gets executed successfully, but will cause Apache to generate the above message in its error log:
以下从 MySQL 抓取数据的代码执行成功,但会导致 Apache 在其错误日志中生成上述消息:
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();
Will there be any dire consequences by ignoring the said error/warning? The code has been running for a week without any ill effects.
Is there anything wrong with the code or is this just a harmless warning?
忽略上述错误/警告会产生什么可怕的后果吗?代码已经运行了一个星期,没有任何不良影响。
代码有什么问题吗,或者这只是一个无害的警告?
Edit
编辑
Code is executed via mod_perl.
代码通过 mod_perl 执行。
回答by Paul Tomblin
You should call $statement->finish();before $db_handle->disconnnect();.
你应该叫$statement->finish();之前$db_handle->disconnnect();。
Normally you don't need to call finish, unless you're not getting all the rows. If you get all the results in a loop using fetchrow_array, you don't call finish at the end unless you aborted the loop.
通常你不需要调用finish,除非你没有得到所有的行。如果使用 获得循环中的所有结果fetchrow_array,则除非中止循环,否则最后不会调用完成。
I'm not sure why the MySQL driver isn't finishing the statement after a fetchall_hashref. The manual suggests that your query might be aborting due to an error:
我不确定为什么 MySQL 驱动程序没有在fetchall_hashref. 该手册建议您的查询可能由于错误而中止:
If an error occurs, fetchall_hashref returns the data fetched thus far, which may be none. You should check $sth->err afterwards (or use the RaiseError attribute) to discover if the data is complete or was truncated due to an error.
如果发生错误,fetchall_hashref 返回到目前为止获取的数据,可能没有。之后您应该检查 $sth->err(或使用 RaiseError 属性)以发现数据是否完整或因错误而被截断。
回答by wds
This is caused by the handle still being active. Normally it should close itself though, but you don't seem to be fetching all the data from it. From the perldocon DBI:
这是由于句柄仍处于活动状态造成的。通常它应该关闭自己,但你似乎没有从中获取所有数据。来自DBI 上的perldoc:
When all the data has been fetched from a SELECT statement, the driver should automatically call finish for you. So you should not normally need to call it explicitly except when you know that you've not fetched all the data from a statement handle. The most common example is when you only want to fetch one row, but in that case the selectrow_* methods are usually better anyway. Adding calls to finish after each fetch loop is a common mistake, don't do it, it can mask genuine problems like uncaught fetch errors.
当从 SELECT 语句中获取所有数据后,驱动程序应自动为您调用完成。所以你通常不需要显式调用它,除非你知道你没有从语句句柄中获取所有数据。最常见的例子是当您只想获取一行时,但在这种情况下, selectrow_* 方法通常更好。在每个 fetch 循环后添加调用完成是一个常见的错误,不要这样做,它可以掩盖真正的问题,如未捕获的 fetch 错误。
回答by veeTrain
Although probably not the reason you got this warning(which is what the manualclaims that it is), I experienced the same warning in slightly different circumstances and wanted to suggest it here rather than opening my own question.
尽管可能不是您收到此警告的原因(这就是手册声称的原因),但我在略有不同的情况下遇到了相同的警告,并想在这里提出建议,而不是提出我自己的问题。
You may find yourself in this scenario if you perform a query to fetch some rows -- but only for the intention of knowing whether or not there are rows that match or not. In my circumstance, we'll update the rows if a match is found and insert otherwise.
如果您执行查询以获取一些行,您可能会发现自己处于这种情况——但只是为了了解是否存在匹配的行。在我的情况下,如果找到匹配项,我们将更新行,否则将插入。
Because nothing is done with the rows that are found, I believe this constitutes a scenario where following the warning's lead is appropriate. Therefore, I call finish()on my select handler before I disconnect.
因为找到的行没有做任何事情,所以我相信这构成了一个场景,遵循警告的引导是合适的。因此,我finish()在断开连接之前调用我的选择处理程序。
Disclaimer: Being new to DBI, there is potentially a better approach. I would have used ->do()except the documentationpointed out that it should notbe used when executed repeatedly -- also discouraged were SELECTstatements for some reason, as well!
免责声明:作为 DBI 的新手,可能有更好的方法。我会使用->do()除了文档指出它不应该在重复执行时使用 -SELECT出于某种原因也不鼓励使用语句!
Here is some perl pseudocode showing what I landed on:
下面是一些 perl 伪代码,显示了我所登陆的内容:
$selectHandler = $dbh->prepare($queryString) or die "Cannot prepare: ".$dbh->errstr;
#Loop through a list of keys to check existence {
$selectHandler.execute($uniqueID);
$found = 0;
$found = $selectHandler->fetch();
if (!$found) {
# Do an insert of $uniqueID
} else {
# Do an update of $uniqueID
}
#}
# Having not done anything with the selectHandler's result (when rows were
# found) close it now that the loop is complete
$selectHandler->finish(); # we don't need you any more select handler!
$dbh->disconnect or warn "Disconnection error: $DBI::errstr\n";
Hope this helps someone else and feel free to correct my approach if I am misleading anyone.
希望这对其他人有所帮助,如果我误导任何人,请随时纠正我的方法。

