2010-04-13 55 views
8

我玩弄錯誤處理,並得到一個小問題。 我使用DBI模塊連接數據庫。Perl:捕獲錯誤無死亡

我通過使用一個調用錯誤的子例程來完成自己的錯誤處理。

我能聽到我自己的模具,進行處理得很好,但,當我的數據庫連接失敗,DBI模塊顯然打印出它自己的芯片:

DBI connect(...) failed: ORA-12154: TNS:could not resolve the connect identifier specified (DBD ERROR: OCIServerAttach) at ...

我怎麼會去追趕呢?

我嘗試使用$SIG{__DIE__}像這樣:

local $SIG{__DIE__} = sub { 
    my $e = shift; 
    print "Error: " .$e; 
}; 

這是我的主要文件的底部,在這個文件我也調用connect子程序可用我自己的模塊中。我也試着把這段代碼放在我的模塊的底部,但它仍然在它的前面打印出錯誤,而不是在其前面沒有

Error:

回答

3

好了,找到了解決辦法,顯然我需要__WARN__,而不是__DIE__和這段代碼是在文件的頂部需要,在拋出的錯誤之前,不像比如我讀說:)

+3

這是正確的,這是一個警告,而不是一個死亡,並且必須首先安裝處理程序。如果將其包裝在'BEGIN {}'中,可以將它安裝在任何模塊中。 – Ether 2010-04-13 14:56:12

+0

也讀了,謝謝你的驗證。 – Pmarcoen 2010-04-13 15:33:30

2

DBI中有很多開關,如PrintError,RaiseError等,您可以調整它們。 見http://search.cpan.org/perldoc?DBI

+0

嗯,是不是有更通用的解決方案?這樣我可以用1個函數捕獲所有其他錯誤。我可能會使用很多有很多方法來輸出錯誤的模塊,我想獨立於此。 – Pmarcoen 2010-04-13 11:18:01

+0

DBI也有一個HandleError方法。或者,如果您將PrintError設置爲false,則RaiseError爲true,則應調用您的(Pmarcoen's)錯誤處理。 – runrig 2010-04-13 14:44:32

0

這不像通用模具捕捉器那樣通用,而是專門針對DBI錯誤處理,我們實際上有我們自己的模塊提供數據庫調用的包裝;並且模塊的一個功能是在每個DBI調用周圍包裝eval(取決於標誌)。

這使我們能夠對數據訪問級別進行自定義錯誤處理,例如查詢重試,統計,自動故障轉移等 - 對代碼的其餘部分都是透明的。

8

DBI connect(...) failed: ORA-12154: TNS:could not resolve the connect identifier specified (DBD ERROR: OCIServerAttach) at ...

How would I go about catching this ?

要捕獲並處理這種級別的錯誤,請以塊形式「eval {...}」使用eval。這將捕獲子代碼中發生的任何死亡。如果eval塊中的代碼死亡,它將設置$ @並且該塊將返回false。如果代碼沒有死掉,$ @將被設置爲''。

通過SIG {WARN}和SIG {DIE}處理信號很麻煩,因爲它們是全球性的,還有競爭條件需要考慮(如果我在處理不同信號時收到信號會發生什麼?基於信號的計算的傳統問題)。您可能正在編寫單線程代碼,因此您不擔心多個事件調用併發問題,但用戶需要考慮(也許他會在嘗試打開DBI連接時發送SIGKILL )

在這種特定情況下,您正在使用DBI。使用DBI,您可以控制發生錯誤時發生的情況,如果它發生死亡,發出警告或無法正常運行並等待您檢查返回狀態。

以下是使用eval {...}的基本示例。

my $dbh = eval { DBI->connect(@args) }; 
if ([email protected]) 
{ 
    #DBI->connect threw an error via die 
    if ([email protected] =~ m/ORA-12154/i) 
    { 
     #handle this error, so I can clean up and continue 
    } 
    elsif ([email protected] =~ m/SOME \s* other \s* ERROR \s+ string/ix) 
    { 
     #I can't handle this error, but I can translate it 
     die "our internal error code #7"; 
    } 
    else 
    { 
     die [email protected]; #re-throw the die 
    } 
} 

以這種方式使用eval有一些小問題,與全局範圍$ @有關。 Try::Tiny cpan頁面有一個很好的解釋。 Try :: Tiny處理最小的Try/catch塊設置,並處理本地化$ @和處理其他邊緣情況。

+0

這就是我最初的方式,但eval並沒有收到我想要報告的警告。因此,我必須使用SIG {WARN}。 – Pmarcoen 2010-04-14 07:45:44

2

SIG{__DIE__}塊包含此:

### Check if exceptions being caught. 
return if $^S; 

這將防止您的處理程序從上一個eval塊內生成模具基於異常的代碼中使用了。