728x90
- 애플리케이션 로직은 DB 드라이버를 통해 커넥션을 조회한다.
- DB 드라이버는 DB와 TCP/IP 커넥션을 연결한다. 물론 이 과정에서 3 way handshake 같은 TCP/IP 연결을 위한 네트워크 동작이 발생한다.
- DB 드라이버는 TCP/IP 커넥션이 연결되면 ID, PW와 기타 부가정보를 DB에 전달한다.
- DB는 ID, PW를 통해 내부 인증을 완료하고, 내부에 DB 세션을 생성한다.
- DB는 커넥션 생성이 완료되었다는 응답을 보낸다.
- DB 드라이버는 커넥션 객체를 생성해서 클라이언트에 반환한다.
커넥션을 새로 만드는 것은 과정도 복잡하고 시간도 많이 많이 소모되는 일이다.
DB는 물론이고 애플리케이션 서버에서도 TCP/IP 커넥션을 새로 생성하기 위한 리소스를 매번 사용해야 한다.
★ 해결 방안 : 커넥션을 관리하는 풀 (커넥션 풀)
- 애플리케이션을 시작하는 시점에 커넥션 풀은 필요한 만큼 커넥션을 미리 확보해서 풀에 보관한다.
- 기본값은 보통 10
- 커넥션 풀에 들어 있는 커넥션은 TCP/IP로 DB와 커넥션이 연결되어 있는 상태이기 때문에 언제든지 즉시 SQL을 DB에 전달 가능


★ 주의할 점은 커넥션을 종료하는 것이 아니라 커넥션이 살아있는 상태로 커넥션 풀에 반환해야 한다는 것이다.
◎ 정리
- 적절한 커넥션 풀 숫자는 서비스의 특징과 애플리케이션 서버 스펙, DB 서버 스펙에 따라 다르기 때문에 성능 테스트를 통해 결정
- 커넥션 풀은 서버당 최대 커넥션 수를 제한 가능하다.
- 대표적인 커넥션 풀 오픈소스는 commons-dbcp2 , tomcat-jdbc pool , HikariCP 등이 있다.
DataSource 이해
- ex) 애플리케이션 로직에서 DriverManager → HikariCP 변경하면 커넥션을 획득하는 애플리케이션 코드도 함께 변경해야 한다. 의존관계가 DriverManager 에서 HikariCP 로 변경되기 때문이다.
★ 해결방안 : DataSource를 이용한 커넥션 획득 방법 추상화

◎ 정리
- 자바는 DataSource 를 통해 커넥션을 획득하는 방법을 추상화했다.
- 애플리케이션 로직은 DataSource 인터페이스에만 의존
- DriverManagerDataSource → 커넥션 풀 변경해도 애플리케이션 로직은 변경하지 않아도 된다.
DataSource 예제1 - DriverManager
DriverManager
DriverManager.getConnection(URL, USERNAME, PASSWORD)
DataSource
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());
}
- DriverManager 는 커넥션을 획득할 때 마다 URL , USERNAME , PASSWORD 같은 파라미터를 계속 전달해야 한다.
- 반면에 DataSource 를 사용하는 방식은 처음 객체를 생성할 때만 필요한 파리미터를 넘겨두고, 커넥션을 획득할 때는 단순히 dataSource.getConnection() 만 호출하면 된다.
설정과 사용의 분리
- 설정: DataSource 를 만들고 필요한 속성들을 사용해서 URL , USERNAME , PASSWORD 같은 부분을 입력하는 것을 말한다.
설정과 관련된 속성들은 한 곳에 있는 것이 향후 변경에 더 유연하게 대처할 수 있다. - 사용: DataSource 의 getConnection() 만 호출해서 사용하면 된다.
DataSource 예제2 - 커넥션 풀
DataSource 커넥션 풀 (HikariCP)
@Test
void dataSourceConnectionPool() throws SQLException, InterruptedException {
//커넥션 풀링: HikariProxyConnection(Proxy) -> JdbcConnection(Target)
HikariDataSource dataSource = new HikariDataSource();
dataSource.setJdbcUrl(URL);
dataSource.setUsername(USERNAME);
dataSource.setPassword(PASSWORD);
dataSource.setMaximumPoolSize(10);
dataSource.setPoolName("MyPool");
useDataSource(dataSource);
Thread.sleep(1000); //커넥션 풀에서 커넥션 생성 시간 대기
}
HikariConfig
- HikariCP 관련 설정을 확인 할 수 있다. 풀의 이름(MyPool)과 최대 풀 수(10)을 확인 가능
◎ 참고 : HikariCP 커넥션 풀에 대한 더 자세한 내용은 다음 공식 사이트를 참고
https://github.com/brettwooldridge/HikariCP
DataSource 적용
MemberRepository
/**
* JDBC - DataSource 사용, JdbcUtils 사용
*/
@Slf4j
public class MemberRepositoryV1 {
private final DataSource dataSource;
public MemberRepositoryV1(DataSource dataSource) {
this.dataSource = dataSource;
}
//save()...
//findById()...
//update()....
//delete()....
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 을 사용하면 커넥션을 좀 더 편리하게 닫을 수 있다.
-
MemberRepository는 DataSource 인터페이스에만 의존하기 때문에 DriverManagerDataSource HikariDataSource 로 변경해도 코드를 전혀 변경하지 않아도 된다. (DI + OCP)
반응형
'Spring > DB 1편' 카테고리의 다른 글
자바 예외 이해 (0) | 2023.08.09 |
---|---|
스프링과 문제 해결 - 트랜잭션 (0) | 2023.08.09 |
트랜잭션 이해 (0) | 2023.08.09 |
JDBC 이해 (0) | 2023.08.09 |
H2 데이터베이스 설정 (0) | 2023.08.09 |