Почему Apache жалуется на то, что моя программа mod_perl «отключение делает недействительным 1 дескриптор активного оператора»? - PullRequest
8 голосов
/ 12 февраля 2009

отключение делает недействительным 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 ]

12 голосов
/ 12 февраля 2009

Вы должны позвонить $statement->finish(); до $db_handle->disconnnect();.

Обычно вам не нужно вызывать finish, если только вы не получаете все строки. Если вы получите все результаты в цикле, используя fetchrow_array, вы не вызовете финиш в конце, если не прервали цикл.

Я не уверен, почему драйвер MySQL не завершает оператор после fetchall_hashref. Руководство предполагает, что ваш запрос может быть прерван из-за ошибки:

Если возникает ошибка, fetchall_hashref возвращает данные, полученные до сих пор, который может быть ни один. Вы должны проверить $ sth-> err впоследствии (или используйте Атрибут RaiseError), чтобы определить, данные полны или были усечены из-за ошибки.

3 голосов
/ 12 февраля 2009

Это вызвано тем, что ручка все еще активна. Обычно он должен сам закрыться, но вы, похоже, не получаете из него все данные. От perldoc в DBI:

Когда все данные были получены из оператора SELECT, драйвер должен автоматически вызвать финиш для вы. Так что вам обычно не нужно называть это явно, кроме случаев, когда вы знаю, что вы не получили все данные из дескриптора оператора. Большинство общий пример, когда вы хотите только получить один ряд, но в этом случае методы selectrow_ * обычно лучше тем не мение. Добавление звонков для завершения после каждый цикл выборки является распространенной ошибкой, не делайте этого, это может замаскировать подлинное такие проблемы, как необработанные ошибки выборки.

0 голосов
/ 04 декабря 2012

Хотя, возможно, причина не в том, что вы получили это предупреждение (как утверждает руководство ), но я столкнулся с тем же предупреждением в несколько других обстоятельствах и хотел предложить его здесь, а не открывать свой вопрос.

Вы можете оказаться в этом сценарии, если выполните запрос для извлечения некоторых строк - но только для того, чтобы узнать, есть ли соответствующие строки или нет. В моих обстоятельствах мы обновим строки, если совпадение найдено, и вставим в противном случае.

Поскольку ничего не сделано с найденными строками, я считаю, что это представляет собой сценарий, в котором следует следовать указаниям предупреждения. Поэтому я вызываю 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";

Надеюсь, это поможет кому-то еще, и не стесняйтесь исправлять мой подход, если я кого-то вводу в заблуждение.

...