데이터베이스 커넥션 풀 개요

데이터베이스 커넥션 풀(Database Connection Pool) 은 애플리케이션과 데이터베이스 간의 연결을 효율적으로 관리하기 위해 사용하는 기술입니다.

  • 문제점: 애플리케이션이 데이터베이스와 연결하기 위해 Connection 객체를 생성하는 과정은 다음과 같은 단계를 포함합니다.

    1. TCP/IP 연결 설정 (3-way handshake)
    2. 데이터베이스 인증
    3. Connection 객체 반환
      이러한 과정은 반복적으로 실행되면 성능 저하를 유발합니다.
  • 해결책: 데이터베이스 커넥션 풀은 애플리케이션 서버 시작 시 여러 개의 연결(Connection 객체)을 미리 생성해 두고, 애플리케이션에서 요청이 발생할 때마다 이를 재사용합니다. 작업이 끝난 후에는 Connection을 닫는 대신 풀에 반환하여 다른 요청에서 재사용할 수 있습니다.


커넥션 풀 동작 구조

  1. 애플리케이션 시작 시:
    • 커넥션 풀은 설정된 수만큼의 데이터베이스 연결을 미리 생성합니다.
  2. 애플리케이션 실행 중:
    • 데이터베이스 작업이 필요할 때 풀에서 Connection 객체를 가져옵니다.
    • 작업 완료 후 해당 Connection 객체를 닫는 대신 풀로 반환합니다.
  3. 애플리케이션 종료 시:
    • 커넥션 풀이 관리 중인 모든 Connection 객체를 닫고 정리합니다.

코드 예제

1. DriverManager 방식 (비효율적)

// 매번 Connection 객체를 생성
Class.forName("com.mysql.cj.jdbc.Driver");

String url = "jdbc:mysql://localhost:3306/sample";
String user = "root";
String password = "password";

// 새로운 Connection 객체 생성
Connection conn = DriverManager.getConnection(url, user, password);

// Connection 사용
// 작업 수행...

conn.close(); // 연결 종료
  • 문제점: 매번 연결을 생성하고 종료해야 하므로, 네트워크 연결 및 인증 단계에서 성능 저하 발생.

2. 커넥션 풀 방식

설정 코드
<%@ page import="javax.naming.Context" %>
<%@ page import="javax.naming.InitialContext" %>
<%@ page import="javax.sql.DataSource" %>
<%@ page import="java.sql.Connection" %>

<%
    Connection conn = null;

    try {
        // JNDI를 사용해 데이터베이스 연결 설정
        Context initCtx = new InitialContext();
        Context envCtx = (Context) initCtx.lookup("java:comp/env");
        DataSource ds = (DataSource) envCtx.lookup("jdbc/mariadb1");

        // 커넥션 풀에서 Connection 객체 가져오기
        conn = ds.getConnection();

        out.println("데이터베이스 연결 성공");
    } catch (Exception e) {
        out.println("데이터베이스 연결 실패: " + e.getMessage());
    } finally {
        if (conn != null) conn.close(); // 커넥션 반환
    }
%>

3. JDBC 활용 (데이터 조회)

jdbc3.jsp
<%@ page import="java.sql.*" %>
<%@ page import="javax.naming.*" %>
<%@ page import="javax.sql.*" %>

<%
    Connection conn = null;
    PreparedStatement pstmt = null;
    ResultSet rs = null;

    StringBuilder sbHtml = new StringBuilder();

    try {
        Context initCtx = new InitialContext();
        Context envCtx = (Context) initCtx.lookup("java:comp/env");
        DataSource ds = (DataSource) envCtx.lookup("jdbc/mariadb1");

        conn = ds.getConnection();

        String query = "SELECT deptno, dname, loc FROM dept";
        pstmt = conn.prepareStatement(query);
        rs = pstmt.executeQuery();

        sbHtml.append("<table border='1'>");
        while (rs.next()) {
            sbHtml.append("<tr>");
            sbHtml.append("<td>").append(rs.getInt("deptno")).append("</td>");
            sbHtml.append("<td>").append(rs.getString("dname")).append("</td>");
            sbHtml.append("<td>").append(rs.getString("loc")).append("</td>");
            sbHtml.append("</tr>");
        }
        sbHtml.append("</table>");
    } catch (Exception e) {
        sbHtml.append("<p>Error: ").append(e.getMessage()).append("</p>");
    } finally {
        if (rs != null) rs.close();
        if (pstmt != null) pstmt.close();
        if (conn != null) conn.close();
    }
%>

<%= sbHtml.toString() %>

커넥션 풀의 장점

  1. 성능 향상:

    • 커넥션 객체 생성 및 종료 과정이 생략되어 애플리케이션 응답 속도가 빨라집니다.
  2. 리소스 효율성:

    • 동일한 Connection 객체를 재사용하므로 리소스를 절약할 수 있습니다.
  3. 관리 용이성:

    • 연결 수를 제어하여 데이터베이스의 과부하를 방지할 수 있습니다.
  4. 안정성:

    • 유효성 검사 등을 통해 항상 유효한 커넥션만 사용.

커넥션 풀 설정

  • 최소 연결 수(min): 애플리케이션 시작 시 생성될 Connection 객체의 수.
  • 최대 연결 수(max): 동시에 처리 가능한 최대 연결 수.
  • 유휴 연결 검사: 사용되지 않는 연결을 주기적으로 정리.
  • 연결 유효성 검사 쿼리: 커넥션이 유효한지 확인.

결론

데이터베이스 커넥션 풀은 데이터베이스와의 연결을 효율적으로 관리하여 애플리케이션 성능을 크게 향상시킵니다. JSP 및 JDBC에서 커넥션 풀을 활용하면 성능과 안정성을 모두 확보할 수 있습니다. 이를 통해 반복적인 연결 생성과 해제 작업을 피하고 효율적인 데이터베이스 작업을 수행할 수 있습니다.


예제 코드

<%--
  Created by IntelliJ IDEA.
  User: leehayeon
  Date: 2024. 11. 8.
  Time: 12:18
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ page import="javax.naming.Context" %>
<%@ page import="javax.naming.InitialContext" %>
<%@ page import="javax.naming.NamingException" %>

<%@ page import="javax.sql.DataSource" %>

<%@ page import="java.sql.Connection" %>
<%@ page import="java.sql.SQLException" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<!-- jdbc1.jsp -->
<%
  Connection conn = null;

  Context initCtx = new InitialContext();

  // 톰캣의 환경변수 값 찾기
  Context envCtx = (Context) initCtx.lookup("java:comp/env");

  // 데이터베이스 풀링에 대한 설정
  DataSource ds = (DataSource) envCtx.lookup("jdbc/mariadb1");

  conn = ds.getConnection();
  out.println("데이터베이스 연결 성공");

  conn.close();
%>
</body>
</html>
<%--
  Created by IntelliJ IDEA.
  User: kevin
  Date: 2024-11-08
  Time: 오후 12:18
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ page import="javax.naming.Context" %>
<%@ page import="javax.naming.InitialContext" %>
<%@ page import="javax.naming.NamingException" %>

<%@ page import="javax.sql.DataSource" %>

<%@ page import="java.sql.Connection" %>
<%@ page import="java.sql.SQLException" %>

<html>
<head>
    <title>Title</title>
</head>
<body>

<!-- jdbc2.jsp -->
<%
    Connection conn = null;

    try {
        Context initCtx = new InitialContext();
        // 톰갯의 환경변수 값
        Context envCtx = (Context) initCtx.lookup("java:comp/env");
        // 데이터베이스 풀링에 설정
        DataSource dataSource = (DataSource) envCtx.lookup("jdbc/mariadb1");

        conn = dataSource.getConnection();
        out.println("데이터베이스 연결 성공");
    } catch (NamingException e) {
        System.out.println("[에러] " + e.getMessage());
    } catch (SQLException e) {
        System.out.println("[에러] " + e.getMessage());
    } finally {
        if (conn != null) conn.close();
    }
%>

</body>
</html>
<JNDI - jdbc3.jsp 소스>
<%--
  Created by IntelliJ IDEA.
  User: kevin
  Date: 2024-11-08
  Time: 오후 12:18
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ page import="javax.naming.Context" %>
<%@ page import="javax.naming.InitialContext" %>
<%@ page import="javax.naming.NamingException" %>

<%@ page import="javax.sql.DataSource" %>

<%@ page import="java.sql.Connection" %>
<%@ page import="java.sql.PreparedStatement" %>
<%@ page import="java.sql.ResultSet" %>
<%@ page import="java.sql.SQLException" %>

<html>
<head>
    <title>Title</title>
</head>
<body>

<!-- jdbc3.jsp -->
<%
    Connection conn = null;
    PreparedStatement pstmt = null;
    ResultSet rs = null;

    StringBuilder sbHtml = new StringBuilder();

    try {
        Context initCtx = new InitialContext();
        Context envCtx = (Context) initCtx.lookup("java:comp/env");
        DataSource dataSource = (DataSource) envCtx.lookup("jdbc/mariadb1");

        conn = dataSource.getConnection();

        String sql = "select deptno, dname, loc from dept";

        pstmt = conn.prepareStatement( sql );

        rs = pstmt.executeQuery();

        // 복사
        sbHtml.append( "<table border='1' cellspacing='0'>" );
        while( rs.next() ) {
            sbHtml.append( "<tr>" );
            sbHtml.append( "<td>" + rs.getString( "deptno" ) + "</td>" );
            sbHtml.append( "<td>" + rs.getString( "dname" ) + "</td>" );
            sbHtml.append( "<td>" + rs.getString( "loc" ) + "</td>" );
            sbHtml.append( "</tr>" );
        }
        sbHtml.append( "<table>" );

    } catch ( NamingException e ) {
        System.out.println( "[에러] " + e.getMessage() );
    } catch ( SQLException e ) {
        System.out.println( "[에러] " + e.getMessage() );
    } finally {
        if ( rs != null ) rs.close();
        if ( pstmt != null ) pstmt.close();
        if ( conn != null ) conn.close();
    }
%>
<%= sbHtml.toString() %>
</body>
</html>

참고: [데이터베이스] Connection Pool이란?

0개의 댓글

Powered by GraphCDN, the GraphQL CDN