http://www.daesangit.com/ditboard/board/read.cgi?board=oralib&y_number=51&nnew=2


   ▒   자료실   ▒    

 이름 관리자 
 등록일 2002/9/21(토) 20:48 
 
 서블렛 + JDBC 연동시 코딩 고려사항 ⑥   
다음과 같은 프로그램 형식을 생각할 수 있다.

Connection conn = null;
Statement stmt = null;
ResultSet rs = null;
try{
conn = ......; //.......(1)
stmt = conn.createStatement(); //.............(2)
rs = stmt.executeQuery("select ....."); // .....(3)
while(rs.next()){
......
}
}
finally {
try {
rs.close(); //........(4)
stmt.close(); //......(5)
......; //......(6)
}catch(Exception e){}
}

위에서 잘못된 내용은 무엇일까?
finally 절에서 rs, stmt, conn을 null check 없이 동일한 try{}catch 절로 실행하고 있다. 예를 들어 (1), (2)번을 거치면서 conn과 stmt 객체까지는 제대로 수행됐으나 (3)번 Query문장 수행중 SQLException이 발생할 수 있다. 그러면 finally 절에서 (4)번 rs.close()를 수행하려 한다. 

하지만 executeQuery가 실패했기 때문에 rs의 reference는 null 이므로 rs.close()시에 NullPointerException이 발생한다. 결국 정작 반드시 수행돼야 할 (5)번, (6)번이 실행되지 않는다. 

따라서 반드시(!) 다음과 같은 형식의 코딩돼야 한다. 

Connection conn = null;
Statement stmt = null;
ResultSet rs = null;
try{
conn = ......;
stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("select .....");
while(rs.next()){
......
}
}
catch(Exception e){
....
}
finally {
if ( rs != null ) try{rs.close();}catch(Exception e){}
if ( stmt != null ) try{stmt.close();}catch(Exception e){}
if ( conn != null ) ......;
}

앞서 언급했듯이 ResultSet은 Statement가 close될 때 자원이 같이 해제되므로 다음과 같이 해도 크게 문제되지 않는다. 

Connection conn = null;
Statement stmt = null;
try{
conn = ......;
stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("select .....");
while(rs.next()){
......
}
rs.close();
}
catch(Exception e){
....
}
finally {
//if ( rs != null ) try{rs.close();}catch(Exception e){}
if ( stmt != null ) try{stmt.close();}catch(Exception e){}
if ( conn != null ) ......;
}

간혹 다음과 같은 코딩은 문제를 야기하지 않을 것이라고 생각하는 사람들도 있다. 

finally{
try{
if ( stmt != null ) stmt.close();
if ( conn != null ) conn.close();
}catch(Exception e){}
}

저명한 책에서조차 위와 같이 코딩돼 있는 경우가 종종 있다. 물론 큰 문제가 있는 것은 아지만 웹애플리케이션서버의 Connection Pool과 연계해 사용할 땐 문제가 될 수 있다. 

만약 stmt.close()시에 Exception이 throw되면 어떻게 할 것인가? 아니 무슨 null 체크까지 했는데, 무슨 Exception이 발생하느냐고 반문할 수도 있지만, 오랜 시간이 걸리는 SQL JOB에 빠져 있다가 Connection Pool의 "Orphan Timeout"을 넘어섰기 때문에 자동으로 해당 Connection을 Pool에 돌려보내거나 marking처리를 해 둘 수 있습니다. 

이 경우라면 stmt.close()시에 해당 웹어플리케이션서버에 특화된 Exception이 발생하게 된다. conn.close()를 타지 못하게 되는 사태가 벌어진다. 따라서 앞서 언급된 대로 하는 것이 좋다. @ 
