天天看點

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裡面,寫在關閉資料庫連接配接之後。