8

切断は、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();
  • 上記のエラー/警告を無視することで、悲惨な結果が生じることはありますか? コードは 1 週間実行されており、悪影響はありません。

  • コードに何か問題がありますか、それとも無害な警告ですか?

編集

コードは 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 ステートメントからフェッチされると、ドライバーは自動的に終了を呼び出します。したがって、ステートメント ハンドルからすべてのデータをフェッチしていないことがわかっている場合を除き、通常は明示的に呼び出す必要はありません。最も一般的な例は、1 行だけをフェッチしたい場合ですが、その場合は通常 selectrow_* メソッドの方が優れています。各フェッチ ループの後に終了する呼び出しを追加することはよくある間違いです。これを行わないでください。キャッチされないフェッチ エラーなどの真の問題が隠される可能性があります。

于 2009-02-12T14:54:38.297 に答える
0

この警告が表示された理由ではないかもしれませんが(マニュアルではそれが主張されています)、私はわずかに異なる状況で同じ警告を経験し、私自身の質問を開くのではなく、ここでそれを提案したいと思いました。

クエリを実行していくつかの行をフェッチすると、このシナリオに遭遇する可能性がありますが、一致する行があるかどうかを知るためだけです。私の状況では、一致するものが見つかった場合は行を更新し、そうでない場合は挿入します。

見つかった行には何も行われないため、これは警告の先頭に従うことが適切であるシナリオを構成すると思います。したがって、finish()切断する前にselectハンドラーを呼び出します。

免責事項: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 に答える