서블렛 + JDBC 연동시 코딩 고려사항 ④

일반입력 :2002/04/18 00:00

이원영

Exception이 발생했을 때도 Connection은 닫혀야 한다 public void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException, SQLException { String id = req.getParameter("id"); Connection conn = DriverManager.getConnection("url...","id","password"); Statement stmt = conn.createStatement(); ResultSet rs = stmt.executeQuery("ssselect * from XXX where id = '" + id + "'"); while(rs.next()) { ...... } rs.close(); stmt.close(); conn.close(); ..... }위에서 잘못된 것은 무엇일까? 특별히 잘못된 것은 없다. 단지 SQL문장에 오타가 있다는 것 뿐이다. SQLException이라는 것은 Runtime 때 발생한다. DB의 조건이 맞지 않거나 개발 기간 중에 개발자의 실수로 SQL문장에 위처럼 오타를 적을 수도 있다. 문제는 Exception이 발생하면 마지막 라인들 즉, rs.close(), stmt.close(), conn.close()가 수행되지 않는다는 것이다. java.sql.Connection은 reference를 잃더라도 JVM(Java Virtual Machine)의 GC(Garbage Collection)의 대상이 아니다. 그렇지 않아도 모자라는 DB연결자원을 특정 애플리케이션이 점유하도록 하지 않기 때문에 DB Connection을 더이상 연결하지 못하게 된다. 따라서 다음처럼 Exception의 발생 유무와 상관없이 java.sql.Connection을 close()하는 로직이 꼭(!) 들어가야 한다. public void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException, SQLException { Connection conn = null; Statement stmt = null; ResultSet rs = null; String id = req.getParameter("id"); try { conn = DriverManager.getConnection("url...","id","password"); stmt = conn.createStatement(); rs = stmt.executeQuery("sselect * from XXX where id = '" + id + "'"); while(rs.next()) { ...... } rs.close(); stmt.close(); } finally { if ( conn != null ) try {conn.close();}catch(Exception e){} } ..... }참고로 실프로젝트의 진단 및 튜닝을 나가보면 처음에는 적절한 응답속도가 나오다가 일정한 횟수 이상을 호출하고 난 뒤부터 엄청 응답시간이 느려진다면 십중팔구는 위처럼 java.sql.Connection 을 닫지 않아서 생기는 문제이다. 가용한 모든 Connection을 연결해 더이상 연결시킬 Connection 자원을 할당할 수 없을 때, 대부분 timewait이 걸리기 때문이다. 일단 DB관련한 작업이 들어오는 것마다 timewait에 빠질 경우, 애플리케이션서버에서 동시에 처리할 수 있는 최대 갯수만큼 호출이 차곡차곡 쌓이는 건 불과 몇분 걸리지 않는다. 그 뒤부터는 애궂은 dummy.jsp조차 호출이 되지 않게 되고, 누군가는 "시스템 또 죽었네"라며 묘한 웃음을 짓곤 한다. @서블렛 + JDBC 연동시 코딩 고려사항 ①서블렛 + JDBC 연동시 코딩 고려사항 ②서블렛 + JDBC 연동시 코딩 고려사항 ③