为什么Apache抱怨我的mod_perl程序“断开连接使1个活动语句句柄无效”?

时间:2009-02-12 14:39:06

标签: mysql perl apache dbi

  

disconnect会使1活动无效   声明句柄(要么毁灭   语句处理或调用完成   他们在断开连接之前)

以下从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();
  • 会有任何可怕的后果吗? 忽略上述错误/警告? 代码已经运行了一个星期 没有任何不良影响。

  • 代码有什么问题 或者这只是一个无害的警告?

修改

代码通过mod_perl执行。

3 个答案:

答案 0 :(得分:12)

您应该在$statement->finish();之前致电$db_handle->disconnnect();

通常您不需要致电finish,除非您没有获得所有行。如果使用fetchrow_array在循环中获得所有结果,则除非中止循环,否则不会在结束时调用finish。

我不确定为什么MySQL驱动程序在fetchall_hashref之后没有完成语句。手册建议您的查询可能因错误而中止:

  

如果发生错误,请输入fetchall_hashref   返回到目前为止提取的数据,   可能没有。你应该检查一下   $ sth->事后错误(或使用   RaiseError属性)以发现是否   数据已完成或被截断   由于错误。

答案 1 :(得分:3)

这是由句柄仍处于活动状态引起的。通常它应该关闭自己,但你似乎没有从中获取所有数据。来自DBI上的perldoc

  

获取所有数据后   从SELECT语句,驱动程序   应该自动调用完成   您。所以你通常不需要   明确地称它为除外   知道你没有拿走所有的   来自语句句柄的数据。最多   常见的例子是你只想要的时候   获取一行,但在那种情况下   selectrow_ *方法通常更好   无论如何。添加调用后完成   每个获取循环都是一个常见错误,   不要这样做,它可以掩盖真实   像未捕获的错误一样的问题。

答案 2 :(得分:0)

虽然可能不是你得到这个警告的原因(这是manual声称它是什么),但我在略有不同的情况下遇到了同样的警告,并想在这里建议而不是打开我自己的问题。

如果您执行查询以获取某些行,您可能会发现自己处于这种情况 - 但仅限于了解是否存在匹配行的行。在我的情况下,如果找到匹配,我们将更新行,否则插入。

因为找不到所发现的行,所以我认为这构成了遵循警告线索的情况。因此,在断开连接之前,我在选择处理程序上调用finish()

免责声明:作为DBI的新手,可能有更好的方法。我会使用->do(),除了the documentation指出它应该在重复执行时使用 - 由于某种原因也不鼓励SELECT语句,以及!

这是一些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";

希望这有助于其他人,如果我误导任何人,请随时纠正我的方法。