커넥션 풀이란 데이터베이스와 연결된 커넥션을 미리 만들어서 풀(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 |
댓글