주니어 기초 코딩공부/Database 기초

[데이터베이스] 커넥션 풀 Connection Pool (feat. mySQL)

jju_developer 2023. 1. 26. 20:39
728x90

보통 

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

 

 특징
• 커넥션을 생성하는 데 드는 연결 시간이 소비되지 않는다.
• 커넥션을 재사용하기 때문에 생성되는 커넥션 수가 많지 않다.

 

메모리를 많은 쓰면 안되기 때문에 데이터 베이스에 연결되는 클라이언트에 대한 커넥션을 제한을 걸어둡니다.

데이터베이스의 서버의 용량에 따라서 제한을 둡니다.

생각보다 커넥션의 메모리의 양이 적습니다.

안 그러면 무한적 허용하게 되면 서버가 죽기 때문에 이렇게 적은 메모리를 할당하는 것입니다.

 

 

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

 

아파치에서 제공하는 커넥션 풀 관련 클래스입니다.

 

(1) 필요한 jar 파일 복사하기
 필요 라이브러리 복사
• Commons-DBCP API : commons-dbcp2-2.1.jar
• Commons-Pool API : commons-pool2-2.4.1.jar
• Commons Logging API : common-logging-1.2.jar

설정경로

 

(2) 커넥션 풀 초기화 서블릿 클래스
 실제 커넥션을 생성할 ConnectionFactory를 생성합니다.
 커넥션 풀로 사용할 PoolableConnection을 생성하는 PoollableConnectionFactory를 생성합니다.
 커넥션 풀의 설정 정보를 생성합니다.
 커넥션 풀을 사용할 JDBC 드라이버를 등록합니다.

web.xml

 

package jdbc;

import java.sql.DriverManager;
import java.util.Properties;

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

import org.apache.commons.dbcp2.BasicDataSource;
import org.apache.commons.dbcp2.BasicDataSourceFactory;
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.ObjectPool;
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.jdbc.Driver");
		} catch (ClassNotFoundException ex) {
			throw new RuntimeException("fail to load JDBC Driver", ex);
		}
	}

	private void initConnectionPool() {
		try {
			String jdbcUrl = 
					"jdbc:mysql://localhost:3306/chap14?" + 
					"useUnicode=true&characterEncoding=utf8";
			String username = "jspexam";
			String pw = "jsppw";

			ConnectionFactory connFactory = 
					new DriverManagerConnectionFactory(jdbcUrl, username, pw);

			PoolableConnectionFactory poolableConnFactory = 
					new PoolableConnectionFactory(connFactory, null);
			poolableConnFactory.setValidationQuery("select 1");

			GenericObjectPoolConfig poolConfig = new GenericObjectPoolConfig();
			poolConfig.setTimeBetweenEvictionRunsMillis(1000L * 60L * 5L);
			poolConfig.setTestWhileIdle(true);
			poolConfig.setMinIdle(4);
			poolConfig.setMaxTotal(50);

			GenericObjectPool<PoolableConnection> connectionPool = 
					new GenericObjectPool<>(poolableConnFactory, poolConfig);
			poolableConnFactory.setPool(connectionPool);
			
			Class.forName("org.apache.commons.dbcp2.PoolingDriver");
			PoolingDriver driver = 
					(PoolingDriver) DriverManager.getDriver("jdbc:apache:commons:dbcp:");
			driver.registerPool("chap14", connectionPool);
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}
}

 

코드 설명 DBCPrint.java

connection풀을 chap14라는 이름으로 만들었는데

 

이게 제대로 만들어져 있는지 검증을 해야겠죠?

 

맨 마지막 코드 봅사다

<%@ page contentType = "text/html; charset=utf-8" %>
<%@ page import = "java.sql.DriverManager" %>
<%@ page import = "java.sql.Connection" %>
<%@ page import = "java.sql.Statement" %>
<%@ page import = "java.sql.ResultSet" %>
<%@ page import = "java.sql.SQLException" %>
<html>
<head><title>회원 목록</title></head>
<body>

MEMBER 테이블의 내용
<table width="100%" border="1">
<tr>
	<td>이름</td><td>아이디</td><td>이메일</td>
</tr>
<%
	
	Connection conn = null;
	Statement stmt = null;
	ResultSet rs = null;
	
	try {
		String jdbcDriver = "jdbc:apache:commons:dbcp:chap14";
		String query = "select * from MEMBER order by MEMBERID";
		conn = DriverManager.getConnection(jdbcDriver);
		stmt = conn.createStatement();
		rs = stmt.executeQuery(query);
		while(rs.next()) {
%>
<tr>
	<td><%= rs.getString("NAME") %></td>
	<td><%= rs.getString("MEMBERID") %></td>
	<td><%= rs.getString("EMAIL") %></td>
</tr>
<%
		}
	} finally {
		if (rs != null) try { rs.close(); } catch(SQLException ex) {}
		if (stmt != null) try { stmt.close(); } catch(SQLException ex) {}
		if (conn != null) try { conn.close(); } catch(SQLException ex) {}
	}
%>
</table>

</body>
</html>

 

둘의 코드는 동일합니다.

둘의 코드를 비교해 봤을 때 훨씬 오른쪽 코드가 간결한 것을 알 수 있죠?

viewMember.jsp

http://localhost:8080/chap14/viewMember.jsp? memberID=jju

멤버 아이디에 jju를 입력했더니 jju에 대한 테이블이 나오죠?

 

데이터베이스에 저장된 member 테이블

데이터베이스에 저장된 member 테이블입니다.

 

반면에 커넥션 풀을 이용한 

viewMemberUsingPool.jsp

http://localhost:8080/chap14/viewMemberUsingPool.jsp

반대로 커넥션 풀을 이용한 코드를 실행하면 바로 

 

전체 테이블을 볼 수 있습니다.

 

그럼 지금까지 connection 풀에 관한 기초 설명이었습니다.

 

 

 

 

 

 

읽어보면 좋은 참고 자료: https://steady-coding.tistory.com/564

728x90