finally被置空導致資料庫連線掛死
今天寫了幾行程式碼,向資料庫插入一篇文章,程式執行表現很好,完全按照我的意願去走,可以寫入時都成功寫入資料庫,該失敗時果斷失敗。可是當我回頭再看程式碼時,突然驚恐萬分。這裡面隱藏了多麼弱智的bug,甚至說是外行的錯誤,可是想了一下,似乎又很有可能出現,一不小心就有可能再次寫出來,所以寫個博警告下自己。
向資料庫插入文章的程式碼,這裡面至少隱藏了三個超級弱智的致命錯誤:
public int insertThreadBeanIntoDB(ThreadBean threadbean){
ErrorTypeBean ErrorType = ErrorTypeBean.getErrorTypeHandle();
/*這一步是必須做的,否則會出異常*/
if(null == threadbean){
return ErrorType.getErrorCodeByErrorType("NULL_POINTER");
}
Connection conn = null;
PreparedStatement ps = null;
int result = 0;
try{
conn = new ConnDB().getConnection();
ps = conn.prepareStatement("insert into thread values(?,?,?,?,?,?,?)");
ps.setString(1, threadbean.getThread_id().toString());
ps.setString(2, threadbean.getTread_title());
ps.setString(3, threadbean.getTread_content());
ps.setString(4, threadbean.getThread_create_time().toString());
ps.setString(5, threadbean.getThread_update_time().toString());
ps.setString(6, threadbean.getThread_hit_number().toString());
ps.setString(7, threadbean.getThread_user().toString());
result=ps.executeUpdate();
if(0 == result){
return ErrorType.getErrorCodeByErrorType("DB_OPERATION_ERROE");
}
}catch(Exception e){
e.printStackTrace();
return ErrorType.getErrorCodeByErrorType("UNKNOWN_ERROR");
}finally{
/*關閉資源*/
this.closeConn();
}
return ErrorType.getErrorCodeByErrorType("NO_ERROR");
}
在try裡面成功操作資料庫後,直接將結果返回;
catch到異常後直接返回錯誤碼;
在程式的最後直接返回成功。
嚴重沒睡醒!
無論是在在try裡面還是在catch裡面返回,都會講finally掛起,導致資料庫連線無法關閉。在上面的寫法下,如果出現錯誤,catch會攔截下來,所以出現錯誤的時候不會有任何不正常的表現,但是finally被置空了;而如果執行成功,則catch無效,可以在最後返回成功,程式也不會出現表面的失敗。而一旦try裡面的返回條件滿足,則try就會將finally置空,撇開上面的try裡面的情況,如果稍微處理複雜點,可能會出現,在操作成功的時候也會全部將finally置空,這時,finally將永遠得不到執行,所有資料庫連線將全部不能關閉。
這種錯誤在執行的時候不會出現任何異常表現,一旦時過境遷,這種錯誤將無從查起,而系統頻繁出現數據庫自然耗盡,解決辦法只有重啟...重啟...再重啟。當然了,也可以通過檢視資料庫連線的使用情況來分析問題的所在。但是問題已經升級不止一個檔次了,小疏忽引發的大問題,不可疏忽。
正確寫法:
public int insertThreadBeanIntoDB(ThreadBean threadbean){
ErrorTypeBean ErrorType = ErrorTypeBean.getErrorTypeHandle();
int operation_code = ErrorType.getErrorCodeByErrorType("NO_ERROR");
/*這一步是必須做的,否則會出異常*/
if(null == threadbean){
return ErrorType.getErrorCodeByErrorType("NULL_POINTER");
}
Connection conn = null;
PreparedStatement ps = null;
int result = 0;
try{
conn = new ConnDB().getConnection();
ps = conn.prepareStatement("insert into thread values(?,?,?,?,?,?,?)");
ps.setString(1, threadbean.getThread_id().toString());
ps.setString(2, threadbean.getTread_title());
ps.setString(3, threadbean.getTread_content());
ps.setString(4, threadbean.getThread_create_time().toString());
ps.setString(5, threadbean.getThread_update_time().toString());
ps.setString(6, threadbean.getThread_hit_number().toString());
ps.setString(7, threadbean.getThread_user().toString());
result=ps.executeUpdate();
if(0 == result){
operation_code = ErrorType.getErrorCodeByErrorType("DB_OPERATION_ERROE");
}
}catch(Exception e){
e.printStackTrace();
operation_code = ErrorType.getErrorCodeByErrorType("UNKNOWN_ERROR");
}finally{
/*關閉資源*/
this.closeConn();
}
return operation_code;
}
如果非得在try-catch裡面返回,name至少應該寫在finally裡面,寫在關閉資料庫連線之後。