8

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 执行。

4

3 回答 3

12

你应该$statement->finish();先打电话$db_handle->disconnnect();

通常你不需要打电话finish,除非你没有得到所有的行。如果使用 循环获得所有结果fetchrow_array,则不会在最后调用完成,除非中止循环。

我不确定为什么 MySQL 驱动程序没有在fetchall_hashref. 该手册建议您的查询可能由于错误而中止:

如果发生错误, fetchall_hashref 会返回到目前为止获取的数据,可能没有。您应该在之后检查 $sth->err(或使用 RaiseError 属性)以发现数据是否完整或由于错误而被截断。

于 2009-02-12T14:43:33.003 回答
3

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

从 SELECT 语句中获取所有数据后,驱动程序应自动为您调用完成。所以你通常不需要显式调用它,除非你知道你没有从语句句柄中获取所有数据。最常见的示例是当您只想获取一行时,但在这种情况下 selectrow_* 方法通常会更好。在每个 fetch 循环之后添加调用完成是一个常见的错误,不要这样做,它可以掩盖真正的问题,例如未捕获的 fetch 错误。

于 2009-02-12T14:54:38.297 回答
0

虽然可能不是您收到此警告的原因(这是手册声称的内容),但我在略有不同的情况下遇到了相同的警告,并想在这里提出建议,而不是提出我自己的问题。

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

因为没有对找到的行进行任何操作,所以我相信这构成了一个适合遵循警告引导的场景。因此,我finish()在断开连接之前调用了我的选择处理程序。

免责声明:作为 DBI 的新手,可能有更好的方法。->do()除了文档指出重复执行时不应使用它之外,我会使用它——出于某种原因也不鼓励使用语句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";

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

于 2012-12-03T21:58:30.117 回答