2009-02-12 25 views
8

disconnect invalidates 1 active statement handle (either destroy statement handles or call finish on them before disconnecting)爲什麼Apache會抱怨我的mod_perl程序「斷開連接使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的執行。

+0

嘿,布賴恩,感謝您編輯標題。我以前讀過你所有的書。 – GeneQ 2009-02-17 09:25:31

回答

12

您應該在$db_handle->disconnnect();之前致電$statement->finish();

通常情況下,你不需要撥打finish,除非你沒有得到所有的行。如果您使用fetchrow_array獲得了循環中的所有結果,那麼除非中止循環,否則不要在最後調用finish。

我不知道爲什麼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.

+0

謝謝,這個伎倆。儘管閱讀O'Reilly DBI書籍和Perl文檔是另一回事。在16分鐘內解決!去stackoverflow! – GeneQ 2009-02-12 15:01:23

+0

感謝您回答我的問題保羅的「爲什麼」部分。 ;-)你應該得到15k的業力。 – GeneQ 2009-02-12 15:16:40

3

這是由手柄仍處於活動狀態引起的。通常情況下,它應該關閉,但是你似乎並沒有從中獲取所有的數據。從perldoc上DBI:

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.

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"; 

希望這可以幫助其他人,並隨時糾正我的方法,如果我誤導任何人。

相關問題