DBCP 설정(MySQL)
오늘은 웹 개발에서 빠질 수 없는 DBCP에 대해 포스팅해보려 합니다.
※설명에 들어가기 앞서 포스팅 내용은 이클립스(Oxygen 버전), 톰캣(8.5 버전), MySQL, jdk 1.8 환경임을 알려드립니다.
DBCP란?
DBCP는 Database Connection Pool의 약자로 데이터 베이스(DB)와 연결을 맺고 있는 Connection 객체를 관리하는 역할을 합니다. 즉, DBCP를 사용하여 우리는 DB에 접근할 수 있습니다.
여기서 JDBC를 사용하여 DB를 연결한 경험이 있다면 궁금점이 생길 수 있습니다.
"JDBC 역시 DB를 이용하기 위해 사용하는 자바 API로 알고 있고, DB에 접근이 가능한데 DBCP를 사용하는 이유는 무엇이고 JDBC와 DBCP의 차이점은 무엇일까?"
답은 간단합니다. JDBC를 조금 더 효율적으로 사용하기 위해서입니다.
사실 저를 포함한 자바를 처음 접하는 사람이라면 보통 아래 그림과 같은 과정으로 JDBC를 이용해서 DB를 사용해본 경험이 많을 것입니다.
① 페이지 요청(DBMS 연결 요청)이 들어왔을 때, DB Connection을 호출
② DB 접속을 위해 JDBC 드라이버를 로드
③ DB 서버 정보(서버 URL, 사용자 아이디, 비밀번호)를 입력하여 DB 연결
④ DB Connection 객체 생성
⑤ 쿼리 수행 후 결과 값 반환
⑥ DB Connection close() ☞ Connection을 닫음(메모리 낭비 방지)
우리가 사용하는 웹은 온전히 한 명의 사용자를 위한 사이트보다는 다수의 사용자가 동시에 이용할 수 있는 사이트가 많습니다. 그런데 다수의 사용자가 사이트를 이용할 때 위의 방식과 같이 DB에 접근하게 되면 무슨 일이 일어날까요?
매번 DB 연결을 위해 JDBC 드라이버를 로드하고 DB Connection 객체를 생성하는 행위를 하게 될 것입니다.(②, ③, ④)
이 현상은 몇 명의 사용자가 아닌 몇 십 또는 몇 백 명의 사용자인 경우 속도 차이가 생길 수 있으며, 서버 부하가 일어날 가능성이 높습니다.
이러한 현상을 방지하기 위해 효율적으로 JDBC를 활용하는 방법이 바로 DBCP입니다.
DBCP를 이용하면 다음과 같이 DB에 접근하게 됩니다.
① 페이지 요청(DBMS 연결 요청)이 들어왔을 때, DB Connection Pool에는 이미 DB Connection 객체가 저장되어 있습니다. (WAS 실행 시 개발자가 설정한만큼의 Connection이 생성됩니다)
② DBCP에서 DB Connection 객체를 가져다 사용
③ 쿼리 수행 후 결과 값 반환
④ DB Connection closes() ☞ Connection을 닫는 것이 아니라 Connection Pool로 반환됩니다.
매번 JDBC 드라이버를 로드하고 DB Connection 객체를 생성하지 않아도 DBCP에서 가져다 사용하면 되기 때문에 빠른 처리 속도를 보이며 DB 서버가 감당할 수 없는 접속 요청은 사전에 차단이 가능합니다. 따라서 DBCP는 웹 개발에 아주 중요한 역할을 한다고 볼 수 있습니다.
그럼 이제 DBCP를 사용하는 방법을 알아보겠습니다.
과정은 설치 및 설정, 구현으로 나누어 보았습니다.
1. 설치 및 설정
1-1) DBCP 라이브러리 다운
http://archive.apache.org/dist/commons/ 사이트에 접속하여 Collections, DBCP, Pool의 zip 파일을 다운받습니다.
박스 표시된 부분을 찾아보면 됩니다.
다운 받은 버전은 Collections4-4.0, dbcp-1.4, pool-1.6입니다.
DBCP는 사용중인 JDK 버전과 연관되므로 자신의 JDK에 맞는 버전을 다운받아야 합니다.
- JDK 1.6 이상 : DBCP 1.4 버전
- JDK 1.5 이하 : DBCP 1.3 버전
참고로 DBCP 1.4에서는 Pool 2.0 이상 사용할 수 없습니다.
collections/를 클릭해보겠습니다.
binaries/ 폴더가 보입니다.
commons-collections4-4.0-bin.zip를 클릭하면 다운받을 수 있습니다.
이러한 과정으로 DBCP와 Pool도 다운받습니다.
1-2) 설정
다운받은 파일의 압축을 풀어보면 아래와 같이 폴더가 생깁니다.
폴더 안에는 화살표처럼 각각의 jar 파일이 존재합니다. 이 jar 파일을 자신의 프로젝트 WEB-INF/lib 폴더에 복사합니다.
2. 구현
Connection Pool을 설정하는 방법은 자바 소스 코드상에서 설정하는 방법과 Pool 설정 파일을 만들어 설정하는 방법이 있습니다. 앞서 언급했듯이 본 포스팅은 자바 소스 코드상에서 Connection Pool을 설정합니다.
먼저 프로젝트 WEB-INF에 있는 web.xml에 DBCP 서블렛을 등록합니다.
내용은 주석을 참고하며 마지막에 <load-on-startup>1</load-on-startup>는 톰캣이 실행될 때 자동으로 실행되게끔 하겠다는 의미입니다.
web.xml
<!-- ###################################### -->
<!-- MySQL Database Connection Pool START -->
<!-- ###################################### -->
<servlet> <!-- DBCP 연동 서블렛 -->
<servlet-name>DBCPool</servlet-name>
<servlet-class>web.common.DBCPool</servlet-class>
<init-param> <!-- Connection Pool 이름 -->
<param-name>poolName</param-name> <!-- 변수명 -->
<param-value>Pool 이름(원하는대로)</param-value> <!-- 변수값 -->
</init-param>
<init-param><!-- JDBC Driver -->
<param-name>jdbcDriver</param-name>
<param-value>org.gjt.mm.mysql.Driver</param-value>
</init-param>
<init-param><!-- MySQL 서버 주소 -->
<param-name>jdbcURL</param-name>
<param-value>jdbc:mysql://localhost:3306/DB명?useSSL=false</param-value>
</init-param>
<init-param><!-- 계정명 -->
<param-name>user</param-name>
<param-value>DB 계정 아이디</param-value>
</init-param>
<init-param><!-- 패스워드 -->
<param-name>password</param-name>
<param-value>DB 계정 비밀번호</param-value>
</init-param>
<init-param><!-- 순간 동시 접속자수 -->
<param-name>maxActive</param-name>
<param-value>100</param-value>
</init-param>
<init-param><!-- 대기중인 접속자수 -->
<param-name>maxIdle</param-name>
<param-value>100</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<!-- MySQL Database Connection Pool END -->
<!-- ###################################### -->
서블렛으로 등록한 DBCPool 클래스는 아래와 같이 작성합니다.
package web.common;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import org.apache.commons.dbcp.ConnectionFactory;
import org.apache.commons.dbcp.DriverManagerConnectionFactory;
import org.apache.commons.dbcp.PoolableConnectionFactory;
import org.apache.commons.dbcp.PoolingDriver;
import org.apache.commons.pool.impl.GenericObjectPool;
public class DBCPool extends HttpServlet {
public void init(ServletConfig config) throws ServletException {
String poolName = config.getInitParameter("poolName"); // Pool 이름
String jdbcDriver = config.getInitParameter("jdbcDriver"); // Driver Class
String jdbcURL = config.getInitParameter("jdbcURL"); // MySQL 서버 주소
String user = config.getInitParameter("user"); // 계정 아이디
String password = config.getInitParameter("password"); // 계정 비밀번호
int maxActive = 0; // 최대 연결수
int maxIdle = 0; // 대기중인 연결수
maxActive = Integer.parseInt(config.getInitParameter("maxActive"));
maxIdle = Integer.parseInt(config.getInitParameter("maxIdle"));
try {
Class.forName(jdbcDriver);
GenericObjectPool connectionPool = new GenericObjectPool(null);
connectionPool.setMaxActive(maxActive); // 최대 동시 연결수
connectionPool.setMaxIdle(maxIdle); // 접속 대기 연결수
ConnectionFactory connectionFactory = new DriverManagerConnectionFactory(jdbcURL, user, password);
PoolableConnectionFactory poolableConnectionFactory = new PoolableConnectionFactory(
connectionFactory,
connectionPool,
null, // statement pool
null, // 커넥션 테스트 쿼리: 커넥션이 유효한지 테스트할 때 사용되는 쿼리.
false, // read only 여부
true); // auto commit 여부
PoolingDriver driver = new PoolingDriver();
driver.registerPool(poolName, connectionPool);
System.out.println("---------------------------------------------------");
System.out.println(" >> DBCP Connection Pool이 실행되었습니다 << ");
System.out.println("---------------------------------------------------");
} catch(Exception ex) {
//throw new ServletException(ex);
ex.printStackTrace();
}
}
}
ServletConfig config는 web.xml에서 설정한 Servlet 파라미터들에 접근할 수 있게 하는 객체입니다.
getInitParameter()으로 <param-name>을 찾아 <param-value>를 리턴받습니다.
Pooling을 위한 JDBC 드라이버를 생성하고 Connection Pool을 등록하는 것입니다.
마지막으로 Connection Pool을 가져다 쓰는 클래스를 만들어보겠습니다.
package web.common;
import java.sql.Connection;
import java.sql.DriverManager;
public class DBConnect {
public Connection getConnection(){
Connection con = null;
try{
String poolName = "jdbc:apache:commons:dbcp:Pool 이름";
con = DriverManager.getConnection(poolName);
}catch(Exception e){
e.printStackTrace();
}
return con;
}
}
DB Connection 객체는 원하는 곳에서 호출하여 사용하면 됩니다.
이제 톰캣을 실행해서 DBCP가 정상적으로 등록이 되었다면 아래와 같은 문구를 확인할 수 있습니다.
DBCP를 사용하는 방법과 예제는 다양하니 개발 환경에 맞게 사용하면 될 것 같습니다 :)