[Camel][JSP] Connection Pool (커넥션 풀) with DBCP
1. Connection Pool(커넥션 풀)이란?
JSP 페이지를 실행할 때마다 Connection을 생성하고 닫는다면 시간적 비용이 많이 들기 때문에 접속자 수가 많은 웹 사이트의 경우 성능 저하가 발생할 수 있습니다. 이러한 성능 저하를 막기 위해서 커넥션 풀이라는 것이 사용됩니다.
커넥션 풀은 데이터베이스와 연결된 Connection을 미리 생성한 뒤 Pool이라는 곳에 저장해 두고, 필요할 때마다 꺼내서 사용한 뒤 사용이 끝나면 다시 Pool에 반환하는 기법입니다. 즉, 데이터베이스의 커넥션이 필요할 때 커넥션을 새로 생성하는 것이 아니기 때문에 생성을 위한 시간적 비용이 절감됩니다. 생성뿐만 아니라 커넥션의 종료를 위해 소모되는 시간도 절감할 수 있습니다.
이러한 특징은 한번에 생성될 수 있는 커넥션의 수를 제한하는 것이고, 이는 동시 접속자의 증가로 인한 웹페이지 다운을 완전하지는 않더라도 어느정도 방지할 수 있습니다.
2. DBCP (DataBase Connection Pool)
2-1. Connection Pool 라이브러리 다운로드 및 추가
DBCP API를 사용하기 위해서는 아래의 라이브러리가 필요합니다. Apache Commons 다운로드 페이지에서 다운받을 수 있습니다. 두 압축파일을 다운로드 받은 후 압축을 풀어보면 그 안에는 jar 형태의 파일이 있습니다. jar 파일을 WEB-INF/lib 디렉터리에 복사해서 넣어줍니다.
- commons-dbcp-버전-bin.zip
- commons-pool-버전-bin.zip
2-2. Connection Pool 설정 파일 작성
다음으로는 커넥션 풀 설정파일을 작성해야 합니다. 아래와 같이 커넥션 풀 설정파일을 작성하겠습니다.
ch2/WEB-INF/classes/pool.jocl
<object class="org.apache.commons.dbcp.PoolableConnectionFactory"
xmlns="http://apache.org/xml/xmlns/jakarta/commons/jocl">
<object class="org.apache.commons.dbcp.DriverManagerConnectionFactory">
<string value="jdbc:mysql://localhost:3306/ch2?useUnicode=true&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=UTC&characterEncoding=utf8"/>
<string value="camel"/>
<string value="1234"/>
</object>
<object class="org.apache.commons.pool.impl.GenericObjectPool">
<object class="org.apache.commons.pool.PoolableObjectFactory" null="true" />
</object>
<object class="org.apache.commons.pool.KeyedObjectPoolFactory" null="true"/>
<string null="true"/>
<boolean value="false"/>
<boolean value="true"/>
</object>
DBMS와 연결할때 사용할 JDBC URL과 사용자 계정, 패스워드를 지정해줍니다. 그리고 커넥션 풀과 관련된 추가 설정 정보 또한 지정해줬습니다.
<string null="true"/>는 커넥션의 유효 여부를 검사하기 위해 사용할 Query입니다. Query를 지정하고 싶다면 <string value="select count(*) from member"/>와 같이 지정할 수 있습니다.
처음 <boolean value="false"/>는 커넥션을 읽기 전용으로 생성할지 말지를 결정하는 부분입니다. false로 지정함으로써 insert, update, delete와 같은 작업을 수행할 수 있습니다.
두번째 <boolean value="true"/>는 커넥션 자동 commit 모드를 설정하는 부분입니다. true로 설정함으로써 자동 commit이 됩니다.
또한 한가지 주의할 점이 있다면 커넥션 설정 파일은 XML 문서로 처리되기 때문에 JDBC URL을 표현할 때 사용되는 '&' 기호 대신에 '&'를 사용한다는 점입니다.
2-3. Connection Pool 초기화
이제 커넥션 풀 설정파일까지 적절할 위치에 위치시켜 주었다면 커넥션 풀을 초기화해줘야 합니다. 커넥션 풀을 사용하기 위해서는 커넥션풀과 관련된 JDBC 드라이버를 로딩해줘야 합니다. 그러므로 아래의 두 드라이버를 로딩해줘야 합니다.
- DBMS에 연결할 때 사용될 JBDC 드라이버
- DBCP API의 JDBC 드라이버
웹 어플리케이션이 시작될 때 자동으로 DBMS JDBC 드라이버를 로딩하는 것처럼, DBCP API의 JDBC 드라이버 역시 웹 어플리케이션이 시작될 때 자동으로 로딩되도록 하는 것이 편리하다고 할 수 있습니다. JDBC 드라이버 로딩과 관련된 내용은 이전 포스팅을 참고하시면 되겠습니다.
2020/03/15 - [JSP] - [Camel][JSP] JDBC 프로그래밍 2부 in JSP
[Camel][JSP] JDBC 프로그래밍 2부 in JSP
이 포스팅은 이전 포스팅과 이어지는 내용입니다. 2020/03/14 - [JSP] - [Camel][JSP] JDBC 프로그래밍 1부 in JSP [Camel][JSP] JDBC 프로그래밍 1부 in JSP JDBC 프로그래밍이 대해 설명하기에 앞서 저는 MySQL..
cameldev.tistory.com
package jdbc.loader;
import javax.servlet.http.HttpServlet;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import java.util.StringTokenizer;
public class DBCPInit extends HttpServlet {
public void init(ServletConfig config) throws ServletException {
try {
String drivers = config.getInitParameter("jdbcdriver");
StringTokenizer st = new StringTokenizer(drivers, ",");
while (st.hasMoreTokens()) {
String jdbcDriver = st.nextToken();
Class.forName(jdbcDriver);
}
Class.forName("org.apache.commons.dbcp.PoolingDriver");
} catch(Exception ex) {
throw new ServletException(ex);
}
}
}
이전 포스팅에서와 마찬가지로 WEP-INF/web.xml 파일에 DBCPInit 클래스에 대한 설정 정보를 추가해 줘야합니다. 그렇게 되면 이제 웹 어플리케이션이 시작될 때 DBCPInit 클래스가 시작되도록 할 수 있습니다.
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee">
<servlet>
<servlet-name>JDBCDriverLoader</servlet-name>
<servlet-class>jdbc.loader.Loader</servlet-class>
<init-param>
<param-name>jdbcdriver</param-name>
<param-value>com.mysql.jdbc.Driver</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet>
<servlet-name>DBCPInit</servlet-name>
<servlet-class>jdbc.loader.DBCPInit</servlet-class>
<init-param>
<param-name>jdbcdriver</param-name>
<param-value>com.mysql.jdbc.Driver</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
</web-app>
2-4. Connection Pool의 Connection 사용
커넥션 풀을 생성하고 초기화 했다면 커넥션풀의 Connection을 이제 사용할 수 있습니다. 커넥션 풀의 Connection은 일반적인 Connection과 사용방법이 동일합니다.
하지만, 한가지 차이점이 있습니다. JDBC URL에서 차이가 있습니다. 일반 커넥션 풀을 사용할 경우 JDBC URL을 아래와 같은 형식으로 입력해줘야 합니다.
String jdbcDriver = "jdbc.apsche:commons:dbcp:/[pool이름]";
저의 경우는 pool.jocl 파일으로 설정한 커넥션 풀을 사용하기 때문에 아래와 같이 코드를 작성했습니다.
String jdbcDriver = "jdbc.apsche:commons:dbcp:/pool";
커넥션 풀에서 생성된 Connection의 close 메소드를 호출하면 일반 커넥션의 경우 커넥션이 종료되지만, 커넥션 풀의 Connection의 경우에는 커넥션 풀로 Connection을 반환합니다.
2-5. Connection Pool의 속성
앞서 작성했던 커넥션 풀 설정 파일인 pool.jocl 에서는 커넥션 풀의 속성을 아무것도 지정하지 않았었습니다. 하지만 DBCP의 커넥션 풀은 다양한 속성을 지정할 수 있으며 지정방법은 아래의 태그 사이에 커넥션 풀 속성 값을 지정해 주면 됩니다.
<object class="org.apache.commons.pool.impl.GenericObjectPool">
<object class="org.apache.commons.pool.PoolableObjectFactory" null="true" />
</object>
속성 값을 지정해 준 예제 코드는 아래와 같습니다.
pool2.jocl
<object class="org.apache.commons.pool.impl.GenericObjectPool">
<object class="org.apache.commons.pool.PoolableObjectFactory"
null="true" />
<int value="10" /> <!-- maxActive -->
<byte value="1" /> <!-- whenExhaustedAction -->
<long value="10000" /> <!-- maxWait -->
<int value="10" /> <!-- maxIdle -->
<int value="3" /> <!-- minIdle -->
<boolean value="true" /> <!-- testOnBorrow -->
<boolean value="true" /> <!-- testOnReturn -->
<long value="600000" /> <!-- timeBetweenEvctionRunsMillis -->
<int value="5" /> <!-- numTestsPerEvictionRun -->
<long value="3600000" /> <!-- minEvictableIdleTimeMillis -->
<boolean value="true" /> <!-- testWhileIdle -->
</object>
각 속성에 대한 설명은 아래의 표를 참고하기실 바랍니다.
속성 | 설명 |
maxActive | 커넥션 풀의 최대 커넥션의 수. DMBS의 수용가능 수준에 맞게 지정해야 성능저하를 막을 수 있다. |
whenExhaustedAction | 커넥션 풀에서 가져올 수 있는 커넥션이 없을 경우의 동작을 결정. |
maxWait | whenExhaustedAction 속성의 값이 1이면 사용되는 대기시간. 음수 입력시 무한 대기. |
maxIdle | 사용되지 않고 풀에 저장될 수 있는 최대 커넥션의 수. 음수일 경우 무한 |
minIdle | 사용되지 않고 풀에 저장될 수 있는 최소 커넥션의 수. |
testOnBorrow | true일 경우 커넥션 풀에 커넥션을 가져올 때 커넥션의 유효 여부 검사 |
testOnReturn | true일 경우 커넥션 풀에 커넥션을 반환할 때 커넥션의 유효 여부 검사 |
timeBetweenEvctionRunsMillis | 사용되지 않은 커넥션을 추출하는 쓰레드의 실행 주기를 지정. 양수일 때만 실행. |
numTestsPerEvictionRun | 사용되지 않는 커넥션을 몇 개 검사할지 지정 |
minEvictableIdleTimeMillis | 사용되지 않는 커넥션을 추출할 때 이 속성에서 지정한 시간 이상 비활성화 상태인 커넥션만 추출. 양수로 입력 되어야지만 이 속성으로 추출 가능. |
testWhileIdle | true일 경우 비활성화 커넥션을 추출할 때 커넥션의 유효 여부를 검사한 후, 유효하지 않은 커넥션은 커넥션 풀에서 제거. |