커넥션 풀과 데이터소스 이해

이동건 (불꽃냥펀치)·2025년 2월 14일
0

커넥션 풀 이해

데이터베이스 커넥션을 매번 획득

  1. 에플리케이션 로직은 DB드라이버를 통해 커넥션을 조회한다
  2. DB 드라이버는 DB와 TCP/IP 커넥션을 연결한다. 물론 이과정에서 3 way handshake 같은 TCP/IP연결을 위한 네트워크 동작이 발생한다
  3. DB 드라이버는 TCP/IP 커넥션이 연결되면 ID,PW와 기타 부가정보를 DB에 전달한다
  4. DB는 ID,PW를 통해 내부 인증을 완료하고 내부에 DB 세션을 생성한다
  5. DB는 커넥션 생성이 완료되었다는 응답을 보낸다
  6. DB 드라이버는 커넥션 객체를 생성해서 클라이언트에 반환한다
  • 이렇게 커넥션을 새롭게 만드는 것은 과정도 복잡하고 시간도 많이 소요된다. 이런 문제를 해결하기 위한 아이디어가 커넥션을 미리 생성해두고 사용하는 커넥션 풀이라는 방법이다.

에플리케이션을 시작하는 시점에 커넥션 풀은 필요한 만큼 커넥션을 미리 확보해서 풀에 보관한다. 보통 얼마나 보관할지는 서비스의 특징과 서버 스펙에 따라 달라진다.

커넥션 풀에 들어있는 커넥션은 TCP/IP로 DB와 커넥션이 연결되어있는 상태이기 때문에 언제든지 즉시 SQL을 DB에 전달 할 수 있다.

커넥션을 모두 사용하고 나면 커넥션을 종료하는 것이 아닌 다음에 다시 사용할 수 있도록 해당 커넥션을 그대로 커넥션풀에 반환하면 된다. 이때 주의해야 할점은 커넥션을 종료하는 것이 아니라 살아있는 상태로 커넥션 풀에 반환해야 한다는 것이다.



DataSource 이해

커넥션을 얻는 방법은 JDBC DriverManager를 직접 사용하거나, 커넥션 풀을 사용하는 등 다양한 방법이 존재한다.

  • 하지만 DriverManager로 커넥션을 획득하다가 커넥션 풀을 사용하는 방법으로 변경하려면 어떻게 해야할까?

  • 예를 들어서 애플리케이션 로직에서 DriverManager 를 사용해서 커넥션을 획득하다가 HikariCP 같은 커넥 션 풀을 사용하도록 변경하면 커넥션을 획득하는 애플리케이션 코드도 함께 변경해야 한다. 의존관계가
    DriverManager 에서 HikariCP 로 변경되기 때문이다. 물론 둘의 사용법도 조금씩 다를 것이다.

커넥션을 획득하는 방법을 추상화

  • 자바에서는 이런 문제를 해결하기 위해 javax.sql.DataSource라는 인터페이스를 제공한다
  • DataSource는 커넥션을 획득하는 방법을 추상화하는 인터페이스이다
  • 이 인터페이스의 핵심 시능은 커넥션 조회 하나이다



DataSource 예제 1

DriverManager로 커넥션 획득

 @Slf4j
  public class ConnectionTest {
      @Test
      void driverManager() throws SQLException {
          Connection con1 = DriverManager.getConnection(URL, USERNAME,PASSWORD);
          Connection con2 = DriverManager.getConnection(URL, USERNAME,PASSWORD);
          log.info("connection={}, class={}", con1, con1.getClass());
          log.info("connection={}, class={}", con2, con2.getClass());
      }
}

DriverManagerDataSource 활용

    @Test
      void dataSourceDriverManager() throws SQLException {
          DriverManagerDataSource dataSource =
          new DriverManagerDataSource(URL,USERNAME, PASSWORD);
			useDataSource(dataSource);
            }
      private void useDataSource(DataSource dataSource) throws SQLException {
          Connection con1 = dataSource.getConnection();
          Connection con2 = dataSource.getConnection();
          log.info("connection={}, class={}", con1, con1.getClass());
          log.info("connection={}, class={}", con2, con2.getClass());
		} 
}
  • 기존 코드와 비슷하지만 DriverManagerDataSourceDataSource를 통해서 커넥션을 획득할 수 있다

  • 필요한 데이터를 DataSource 가 만들어지는 시점에 미리 다 넣어두게 되면, DataSource 를 사용하는 곳에서는 dataSource.getConnection() 만 호출하면 되므로,
    URL , USERNAME , PASSWORD 같은 속성들에 의존하지 않아도 된다. 그냥 DataSource 만 주입받아서
    getConnection() 만 호출하면 된다.

  • 리포지토리(Repository)는 DataSource 만 의존하고, 이런 속성을 몰라도 된다.



DataSource 예제2

데이터소스 커넥션 풀 추가

@Test
  void dataSourceConnectionPool() throws SQLException, InterruptedException {

	HikariDataSource dataSource = new HikariDataSource(); 	
    dataSource.setJdbcUrl(URL);
	dataSource.setUsername(USERNAME);
    dataSource.setPassword(PASSWORD); 
    dataSource.setMaximumPoolSize(10); 
    dataSource.setPoolName("MyPool");
      useDataSource(dataSource);
	Thread.sleep(1000); //커넥션 풀에서 커넥션 생성 시간 대기
    }
  • HikariCp 커넥션 풀을 사용
  • 커넥션 풀 최대 사이즈를 10으로 지정하고 풀의 이름을 MyPool이라고 지정
  • 커넥션 풀에서 커넥션을 생성하는 작업은 에플리케이션 실행 속도에 영향을 주지 않기 위해 별도의 스레드에서 작동한다



DataSource 적용

MemberRepositoryV0 => MemberRepositoryV1

@Slf4j
  public class MemberRepositoryV1 {
      private final DataSource dataSource;
      public MemberRepositoryV1(DataSource dataSource) {
          this.dataSource = dataSource;
		}
     private void close(Connection con, Statement stmt, ResultSet rs) {
        JdbcUtils.closeResultSet(rs);
        JdbcUtils.closeStatement(stmt);
        JdbcUtils.closeConnection(con);
	}
    private Connection getConnection() throws SQLException {
        Connection con = dataSource.getConnection();
        log.info("get connection={}, class={}", con, con.getClass());
        return con;
	} 
}
  • DataSource 의존관계 주입
  • JdbcUtils 편의 메서드 변경








출처: https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-db-1

profile
자바를 사랑합니다

0개의 댓글

관련 채용 정보