2010-12-20 7 views
11

다른 사람들의 코드를 리팩토링하고 있습니다. 내가 주목하는 한 가지는 시스템이 연결 풀에서 연결을 얻는 방법에 관한 것입니다.연결 풀에서 데이터베이스 연결 얻기

샘플은 다음과 같습니다. 서비스 메소드를 호출 할 때마다 시스템은 JNDI에서 데이터 소스에 대한 컨텍스트 검색을 수행합니다.

public class CheckinServlet extends HttpServlet { 

    public void doPost(HttpServletRequest request, HttpServletResponse response) 
      throws ServletException, IOException { 

     try { 
      //Obtain Connection 
      InitialContext initialContext = new InitialContext(); 
      javax.sql.DataSource ds = (javax.sql.DataSource) initialContext 
        .lookup("jdbc/mysqldb"); 
      java.sql.Connection conn = ds.getConnection(); 
      //business logic 
      //redirect 
     } finally { 
      conn.close(); 
     } 
    } 
} 

매번이 작업을 수행 할 때 성능이 저하된다고 생각합니다. 연결 풀에서 연결을 검색하는 방법에 대한 다른 방법을 생각 중입니다.

서블릿의 init() 메서드를 사용하려고 생각하고 있지만 최적이 아니라고 생각합니다.

답변

15

많은 서블릿 중 init()이 매번 대신 # ServletContextListener 번에 한번 있습니다. contextInitialized() 메서드는 webapp를 시작할 때 한 번만 실행됩니다.

public class Config implements ServletContextListener { 
    private static final String ATTRIBUTE_NAME = "config"; 
    private DataSource dataSource; 

    @Override 
    public void contextInitialized(ServletContextEvent event) { 
     ServletContext servletContext = event.getServletContext(); 
     String databaseName = servletContext.getInitParameter("database.name"); 
     try { 
      dataSource = (DataSource) new InitialContext().lookup(databaseName); 
     } catch (NamingException e) { 
      throw new RuntimeException("Config failed: datasource not found", e); 
     } 
     servletContext.setAttribute(ATTRIBUTE_NAME, this); 
    } 

    @Override 
    public void contextDestroyed(ServletContextEvent event) { 
     // NOOP. 
    } 

    public DataSource getDataSource() { 
     return dataSource; 
    } 

    public static Config getInstance(ServletContext servletContext) { 
     return (Config) servletContext.getAttribute(ATTRIBUTE_NAME); 
    } 
} 

구성 web.xml에서 다음과 같이 다음과 같이

<context-param> 
    <param-name>database.name</param-name> 
    <param-value>jdbc/mysqldb</param-value> 
</context-param> 
<listener> 
    <listener-class>com.example.Config</listener-class> 
</listener> 

당신은 당신의 서블릿에서 그것을 얻을 수 있습니다 (init() 또는 doXXX() 방법을 선택) :

DataSource dataSource = Config.getInstance(getServletContext()).getDataSource(); 

내가 좋겠 그러나 리팩터링은 JDBC 코드가 서블릿이 아닌 자체 클래스에 배치되어야한다. DAO 패턴을 조회하십시오.

+1

안녕하세요, 항상 자세한 답변을 주셔서 감사합니다. 그러나 한가지는 저를이 문제에 대해 계속 생각하게합니다. Datasource 객체를 컨텍스트 와이드 매개 변수로 배치하는 이유는 무엇입니까? 우리는 단지 getDataSource() 메소드를 정적으로 만든다. 나는이 답변을 정말 좋아하지만 이것을하기위한 이유를 더 배우고 싶다. 고맙습니다.. –

+0

그것도 좋은 디자인을 참조하십시오. 'DataSource'는 하나의'Config' 인스턴스에만 국한되며, 여러 개의'Config' 인스턴스에는 국한되지 않습니다. 이 특별한 경우에는 하나만 존재합니다. – BalusC

+0

contextDestroyed (ServletContextEvent)가 호출되면 데이터베이스 연결이 닫힙니 까? –

3

내가 과거에 사용했던 방법은 데이터 소스를 보유하고

, 예를 들어 싱글 톤 클래스를 만드는 것입니다

public class DatabaseConnectionManager { 

    DataSource ds; 

    public void init() { 
     InitialContext initialContext = new InitialContext(); 
     ds = (javax.sql.DataSource)initialContext.lookup("jdbc/mysqldb"); 
    } 

    public Connection getConnection() { 
     if(ds == null) init(); 

     return ds.getConnection(); 
    } 
} 

즉, jndi 조회 오버 헤드를 제거하여 데이터 원본에 대한 공유 참조가 있음을 의미합니다.

2

덧붙여 말하자면, Service Locator이라는 디자인 패턴이 있습니다.이 패턴은 기본적으로 JNDI 객체를 보유하고있는 "서비스"라는 레지스트리를 포함하는 싱글 톤입니다.

기본적으로 개체가 레지스트리에서 발견되지 않으면 서비스는 JNDI 풀에서 가져 와서 레지스트리에 등록됩니다. 다음 호출은 단순히 레지스트리에서 객체를 가져옵니다.

희망이 도움이됩니다.

3

방금이 테스트를 수행 한 결과 jndi 조회 시간이 그다지 중요하지 않음을 알았습니다. 약 1 초 만에 50.000 개의 조회가 있습니다.

많은 경우 DataSource 캐싱의 이유가 전혀 없습니다.

캐싱의 문제는 데이터 소스 정의와 관련된 사항을 변경하면 앱을 다시 시작해야하는 부실 데이터 소스로 끝날 수 있다는 것입니다.