본문 바로가기
SSR/Servlet & JSP

DBCP를 이용해서 커넥션 풀 사용하기

by oncerun 2020. 5. 20.
반응형

커넥션 풀이란 데이터베이스와 연결된 커넥션을 미리 만들어서 풀(pool) 속에 저장해 두고 필요할 경우 커넥션을 풀(pool)에서 가져와 쓰고 다시 풀(pool)에 반환하는 기법입니다.

 

커넥션 풀은 풀 속에 미리 커넥션이 생성되어있기 때문에 커넥션을 생성하는 데 드는 연결 시간을 줄일 수 있습니다.

커넥션을 계속해서 재사용하기 때문에 생성되는 커넥션 수가 일정하게 유지됩니다.

 

우리가 MySQL을 이용해 커넥션을 얻는다고 한다면 아래 코드와 같이 연결하게 된다.

	try {
		Class.forName("com.mysql.jdbc.Driver");
	} catch (ClassNotFoundException ex) {
		ex.printStackTrace();
	}
	
	Connection con = null;
	Statement st = null;
	ResultSet rs = null;
	try {
		String jdbcDriver = "mysql 서버";
		String dbId = "아이디";
		String dbPwd = "비밀번호";
		String query ="sql문";
		
		con = DriverManager.getConnection(jdbcDriver,dbId,dbPwd);
		st = con.createStatement();
		rs = st.executeQuery(query);
		
		while(rs.next()) {
		}
		} catch (Exception e) {
			
	}finally{
		if(rs != null)try {rs.close();}catch(SQLException ex) {}
		if(st != null)try {st.close();}catch(SQLException ex){}
		if(con != null)try {con.close();}catch(SQLException ex) {}
	}
	

 

MVC 패턴에서 비즈니스 영역의 로직을 처리하는 모델 부분에서 작업이 필요할 때마다 커넥션을 생성해서 사용했다면, JSP페이지를 실행할 때마다 커넥션을 생성하고 닫는데 시간이 소모되기 때문에 동시 접속자가 많은 웹 사이트에서는 성능적으로 낮아집니다. 

 

이러한 문제를 해결하는 일반적인 방식은 커넥션 풀 기법을 사용하는 것입니다.

 

여러 라이브러리 중 저는 오픈 소스 프로젝트인 DBCP API를 이용해보겠습니다.

 

준비물 

commons-dbcp2... bin.zip (자바 버전에 따라 선택하시면 됩니다.)

commons-pool2... bin.zip(버전은 알맞게 선택하시면 됩니다.)

commons-logging... bin.zip(버전은 알맞게 선택하시면 됩니다.)

 

저는 이클립스를 이용하므로 WEB-INF/lib 폴더에. jar파일을 복사해줍니다.

 

사용 방법 

 

1. 커넥션이 풀이 내부에서 사용할 JDBC 드라이버를 로딩합니다.(MySQL)

 

private void loadJDBCDriver() {
		try {

			Class.forName("com.mysql.cj.jdbc.Driver");
			
		} catch (Exception ex) {
			throw new RuntimeException(ex);
		}
		
	}

 

2. 커넥션 풀이 새로운 커넥션을 생성할 때 사용할 커넥션 팩토리를 생성합니다. MySQL에 연결할 때 사용할 JDBC URL, DB계정, DB비밀번호를 생성자로 지정합니다.

 

DBCP는 커넥션 풀에 커넥션을 보관할 때 PoolableConnection을 사용합니다. 이 클래스는 실질적인 커넥션을 보관하고 있으며, 커넥션 풀을 관리하는데 필요한 기능을 추가적으로 제공합니다.

close()를 사용할 경우 실제 커넥션을 종료하지 않고 커넥션 풀에 반환하도록 하는 기능... 등등

ConnectionFactory conFactory = 
					new DriverManagerConnectionFactory(url,user,pwd);
			PoolableConnectionFactory poolableConFactory =
					new PoolableConnectionFactory(conFactory,null);
			poolableConFactory.setValidationQuery("select 123");

* poolableConFactory.setValidationQuery("select 123")

-커넥션에는 유효시간을 지정해 줄 수 있습니다. 유효시간이 지난 커넥션은 DBMS와 연결을 종료합니다.

 커넥션 풀의 모든 연결이 끊긴 상태에서 DB에 연결할 수 없기 때문에 익셉션이 발생합니다.

따라서 커넥션 풀은 커넥션의 연결이 유효한지를 검사할 수 있는 기능인 setValidationQuery()를 제공해 일정 주기로 커넥션을 검사할 수 도 있으며 커넥션을 풀에서 꺼내올 때 검사하기도 합니다. 

select 123의 쿼리를 사용해 검사합니다.

 

 

 

3. 커넥션 풀의 설정 정보를 생성합니다. 

 

GenericObjectPoolConfig poolConfig = new GenericObjectPoolConfig();
			poolConfig.setTimeBetweenEvictionRunsMillis(1000L * 60L * 5L);
            //유효 커넥션 검사 주기(5분)
			poolConfig.setTestWhileIdle(true);
            //보관중인 커넥션이 유효한지 검사할 여부
			poolConfig.setMinIdle(4);
            //최소 커넥션개수
			poolConfig.setMaxTotal(10);
            //최대 커넥션개수

 

 

4. 커넥션 풀을 생성합니다. 

GenericObjectPool<PoolableConnection> conPool =
					new GenericObjectPool(poolableConFactory,poolConfig);
					poolableConFactory.setPool(conPool);

생성자는 PoolbleConnection을 생성할 때 사용되는 팩토리와, 커넥션 풀 설정을 파라미터로 전달받습니다.

생성된 커넥션 풀을 팩토리에 연결해줍니다.

 

 

5. 커넥션 풀 드라이버에 생성한 커넥션 풀을 등록합니다. 

Class.forName("org.apache.commons.dbcp2.PoolingDriver");
			PoolingDriver driver = (PoolingDriver) 
			DriverManager.getDriver("jdbc:apache:commons:dbcp");
			driver.registerPool("webprj", conPool);

이름을 webprj로 주었으며 이 경우 JDBC URL은 "jdbc:apache:commons:dbcp:webprj"가 됩니다.

 

6. 서블릿의 init메서드를 오버라이드 해 웹 애플리케이션이 구동할 때 서블릿을 실행하도록 설정합니다.

 

package webprj.jdbc;

import java.sql.DriverManager;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;

import org.apache.commons.dbcp2.ConnectionFactory;
import org.apache.commons.dbcp2.DriverManagerConnectionFactory;
import org.apache.commons.dbcp2.PoolableConnection;
import org.apache.commons.dbcp2.PoolableConnectionFactory;
import org.apache.commons.dbcp2.PoolingDriver;
import org.apache.commons.pool2.impl.GenericObjectPool;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;




public class DBCPInit  extends HttpServlet{

	@Override
	public void init() throws ServletException {
		
		loadJDBCDriver();
		initConnectionPool();
	}

	private void loadJDBCDriver() {
		try {

			Class.forName("com.mysql.cj.jdbc.Driver");
			
		} catch (Exception ex) {
			throw new RuntimeException(ex);
		}
		
	}

	private void initConnectionPool() {
		
		try {
			String url = "jdbc:mysql:비공개입니다.";
						
			String user ="비공";
			String pwd = "비공";
			
			ConnectionFactory conFactory = 
					new DriverManagerConnectionFactory(url,user,pwd);
			
			PoolableConnectionFactory poolableConFactory =
					new PoolableConnectionFactory(conFactory,null);
			
			poolableConFactory.setValidationQuery("select 123");
			
			
			GenericObjectPoolConfig poolConfig = new GenericObjectPoolConfig();
			poolConfig.setTimeBetweenEvictionRunsMillis(1000L * 60L * 5L);
			poolConfig.setTestWhileIdle(true);
			poolConfig.setMinIdle(4);
			poolConfig.setMaxTotal(10);
			
			GenericObjectPool<PoolableConnection> conPool =
					new GenericObjectPool(poolableConFactory,poolConfig);
			poolableConFactory.setPool(conPool);
			
			Class.forName("org.apache.commons.dbcp2.PoolingDriver");
			PoolingDriver driver = (PoolingDriver) 
					DriverManager.getDriver("jdbc:apache:commons:dbcp:webprj");
			driver.registerPool("webprj", conPool);
			
		}catch(Exception e) {
			throw new RuntimeException(e);
		}
		
	}
	
}

 

 

web.xml 설정

<servlet>
  <servlet-name>DBCPInit</servlet-name>
  <servlet-class>webprj.jdbc.DBCPInit</servlet-class>
  <load-on-startup>1</load-on-startup>
  </servlet>

 

7. 커넥션 풀로부터 커넥션을 사용하기

 

DBCP는 커넥션 풀을 위한 JDBC 드라이버인 PoolingDriver가 존재합니다.

PoolingDriver을 통해 커넥션을 가져올 때 지정해준 이름을 가지고 URL을 사용합니다

 

String jdbcDriver = "jdbc:apache:commons:dbcp:webprj";

Connection con = DriverManager.getConnection(jdbcDriver);

 

String sql = "SELECT NUM,TITLE,WRITER_ID,REGDATE,HIT FROM USER_NOTICE WHERE Sorted_Food = ?";
		String jdbcDriver = "jdbc:apache:commons:dbcp:webprj";

		try (Connection con = DriverManager.getConnection(jdbcDriver);
				PreparedStatement st = con.prepareStatement(sql);
				ResultSet rs = st.executeQuery();) 
               	{
				st.setString(1, kind);
				Notice notice = null;
				List<Notice> noticeList = new ArrayList();

			while (rs.next()) {
				notice = new Notice(
                rs.getInt("NUM"),
                rs.getString("TITLE"),
                rs.getString("WRITER_ID"),
				rs.getDate("REGDATE"),
                rs.getInt("HIT"));

				noticeList.add(notice);
			}

			return noticeList;
		}

*(try-with-resources) 사용. 자동 close() 자바 7.0부터 지원.

반응형

'SSR > Servlet & JSP' 카테고리의 다른 글

서블릿 3.0 파일 업로드  (0) 2020.05.30
Filter  (0) 2020.05.24
JSP SCOPE  (0) 2020.05.13
HttpServletRequest/Response  (0) 2020.05.09
JSTL  (0) 2020.04.28

댓글