YS's develop story

싱글톤 vs HikariCP, Connection 관리 부분에서 어떤 차이점이 있을까 본문

Java

싱글톤 vs HikariCP, Connection 관리 부분에서 어떤 차이점이 있을까

Yusang 2025. 5. 1. 20:40

 

 

 

package util;

import io.github.cdimascio.dotenv.Dotenv;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;

public class DBUtil {
    private static final Dotenv dotenv = Dotenv.load();
    private static final String URL = dotenv.get("DB_HOST");
    private static final String DB_USER = dotenv.get("DB_NAME");
    private static final String DB_PASSWORD = dotenv.get("DB_PW");

    // DB 연결 메서드
    public static Connection getConnection() throws SQLException {
        return DriverManager.getConnection(URL, DB_USER, DB_PASSWORD);
    }
}
public class LendingBookDao {

    public int insertLending(Long bookId, Long userId, LocalDateTime dueDate) {
        String sql = LendingBookSql.INSERT;

        try (Connection connection = DBUtil.getConnection();
             PreparedStatement preparedStatement = connection.prepareStatement(sql)) {

            preparedStatement.setLong(1, bookId);
            preparedStatement.setLong(2, userId);
            preparedStatement.setTimestamp(3, Timestamp.valueOf(dueDate));
            preparedStatement.setInt(4, LendingStatus.IS_BORROWED);

            //영향을 받은 행의 갯수를 출력하게 된다.
            return preparedStatement.executeUpdate();

        } catch (SQLException e) {
            e.printStackTrace();
            return ResultCode.IS_ERROR;
        }
    }
 }

싱글톤, HikariCp을 모두 적용하지 않은 순수 JDBC 코드

 

 

 

✅ 커넥션 관리: 싱글톤 vs HikariCP 차이점

JDBC만을 활용하는 프로젝트를 진행하다가, 매번 DB와 연결하는 Connection 부분을 싱글톤 패턴으로 바꾸려고 하던 중,
예전에 사용했던 Hikari 커넥션 풀이 떠올라 둘의 차이를 비교해 보기 위해 이 글을 작성하게 되었습니다.


💡 DB 커넥션 관리는 왜 중요한가?

DB 연결을 매번 새로 만드는 것은 성능에 매우 안 좋습니다.
DB 연결(Connection)은 리소스를 많이 소모하는 작업이기 때문에,
매번 새로 만들기보다는 재사용 가능한 커넥션 풀(Connection Pool)을 활용하는 것이 효율적입니다.


🔧 HikariCP 적용 전후 코드

적용 전 (DB 커넥션)

package util;

import io.github.cdimascio.dotenv.Dotenv;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;

public class DBUtil {
    private static final Dotenv dotenv = Dotenv.load();
    private static final String URL = dotenv.get("DB_HOST");
    private static final String DB_USER = dotenv.get("DB_NAME");
    private static final String DB_PASSWORD = dotenv.get("DB_PW");

    // DB 연결 메서드
    public static Connection getConnection() throws SQLException {
        return DriverManager.getConnection(URL, DB_USER, DB_PASSWORD);
    }
}

 

 

싱글톤 적용 (DB 커넥션)

package util;

import io.github.cdimascio.dotenv.Dotenv;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;

public class DBUtil {
    private static final DBUtil instance = new DBUtil();

    private final String URL;
    private final String DB_USER;
    private final String DB_PASSWORD;

    // private 생성자
    private DBUtil() {
        Dotenv dotenv = Dotenv.load();
        this.URL = dotenv.get("DB_HOST");
        this.DB_USER = dotenv.get("DB_NAME");
        this.DB_PASSWORD = dotenv.get("DB_PW");
    }

    // 인스턴스를 반환하는 메서드
    public static DBUtil getInstance() {
        return instance;
    }

    // DB 연결 메서드
    public Connection getConnection() throws SQLException {
        return DriverManager.getConnection(URL, DB_USER, DB_PASSWORD);
    }
}

 

HikariCP 커넥션 풀 적용 후 

package util;

import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import io.github.cdimascio.dotenv.Dotenv;

import java.sql.Connection;
import java.sql.SQLException;

public class DBUtil {

    private static final HikariDataSource dataSource;
    private static final Dotenv dotenv = Dotenv.load();

    // HikariCP 설정
    static {
        // Dotenv 라이브러리로 환경 변수 로드
        Dotenv dotenv = Dotenv.load();

        // HikariCP 설정
        HikariConfig config = new HikariConfig();

        // .env 파일에서 DB 연결 정보 가져오기
        config.setJdbcUrl(dotenv.get("DB_HOST"));
        config.setUsername(dotenv.get("DB_NAME"));
        config.setPassword(dotenv.get("DB_PW"));

        // 커넥션 풀 사이즈 설정
        config.setMaximumPoolSize(10);

        // 설정된 데이터소스를 이용하여 커넥션 풀 초기화
        dataSource = new HikariDataSource(config);
    }

    // DB 연결 메서드
    public static Connection getConnection() throws SQLException {
        return dataSource.getConnection();
    }
}

📌 커넥션 풀의 개념과 장점

커넥션 풀(Connection Pool)은 미리 여러 개의 DB 연결을 만들어 두고,
필요할 때마다 꺼내서 쓰고 다시 돌려주는 방식입니다.

 

커넥션 풀을 사용하면?

  • ✅ 커넥션 생성 비용 최소화
  • ✅ 연결/해제 과정을 줄여 성능 향상
  • 멀티스레드 환경에 안전
  • ✅ 설정에 따라 유휴 연결, 타임아웃 등 관리 가능

🔍 싱글톤 방식 vs HikariCP 비교

✅ 1. 싱글톤 패턴으로 Connection 관리

설명:

싱글톤은 애플리케이션 전체에서 단 하나의 Connection 객체만 사용하도록 만드는 방식입니다.

장점:

  • 구현이 매우 간단함.
  • 메모리 낭비를 막고, 단일 객체를 통해 일관된 DB 접근 가능.

단점:

  • DB 연결을 계속 유지하므로, 연결이 끊기거나 유휴 상태가 오래되면 장애 가능성이 큼.
  • 멀티스레드 환경에 부적합: 여러 요청이 하나의 Connection을 공유하면 동시 처리 시 충돌 발생.
  • 트랜잭션 분리가 어려움.

적합한 상황:

  • 단일 사용자 / 테스트 환경 / 간단한 애플리케이션.

✅ 2. HikariCP (Connection Pool)

설명:

HikariCP는 JDBC 연결을 미리 여러 개 만들어 놓고, 요청마다 풀에서 빌려 쓰고 반납하는 방식입니다.

장점:

  • 고성능, 경량 커넥션 풀: 현재 가장 빠르고 널리 사용됨.
  • 스레드 세이프: 다중 사용자 환경에 적합.
  • 풀링 된 커넥션 재사용 → 커넥션 생성/종료 오버헤드 감소.
  • 연결 유휴 시간, 타임아웃, 최대 수 제한 등 다양한 설정 가능.

단점:

  • 설정이 약간 복잡할 수 있음.
  • 메모리를 약간 더 사용함 (여러 커넥션 유지하므로).

적합한 상황:

  • 웹 애플리케이션, 동시 접속이 많은 서비스, 프로덕션 환경.

 

✅ 결론

  • 테스트 용도학습 목적이라면 싱글톤으로도 충분합니다.
  • 하지만, 실제 운영 환경이라면 반드시 HikariCP 같은 커넥션 풀 라이브러리 사용을 권장합니다.
  • 특히 Spring Boot와 같이 프레임워크에서 기본 지원하기 때문에 설정만 해주면 쉽게 사용할 수 있습니다.

🔗 참고

 

 

 

 

 

Comments