일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 |
- 그래프 이론
- 자료 구조
- Spring Security
- 너비 우선 탐색
- n과 m
- 프로젝트
- 알고리즘
- 수학
- MYSQL
- 구현
- 브루트포스 알고리즘
- springboot
- 다이나믹 프로그래밍
- 문자열
- JPA
- 재귀
- 백트래킹
- 소수 판정
- SWEA
- Vue
- 정보처리기사
- dfs
- 그래프 탐색
- 깊이 우선 탐색
- 프로그래머스
- 스택
- DB
- 정수론
- 백준
- 배포
- Today
- Total
영원히 남는 기록, 재밌게 쓰자
커넥션 풀과 데이터 소스를 이해 해보자 본문
저번 실습에서 JDBC 표준 인터페이스를 통해 DB 연결 실습을 해보았다.
잠깐 복습을 해보면
- 커넥션 연결
- SQL 전달
- 결과 응답 반환
이 3가지를 활용하여 DB를 사용한다. 근데 클라이언트 입장에서 DB를 사용하는 로직이 요청을 한번 할 때 마다 계속해서 DB 연결 정보들을 TCP/IP, 연결정보 넘기고,,, 귀찮은 로직들이 계속 된다.
커넥션 하나를 얻기 위한 시간이 소모될 것이고 이는 곳 응답 성능에 영향을 미칠 수 있다.
이를 해결할 수 있는 방법은 커넥션을 미리 생성 해놓으면 어떨까?에 대한 생각에서 나온 기술이 커넥션 풀이다.
커넥션 풀
커넥션 풀은 커넥션을 미리 생성하고 관리해주며 커넥션이 필요할 때 연결 과정을 거치지 않고 미리 생성된 커넥션을 넘겨주는 역할을 수행한다.
미리 생성하는 커넥션의 갯수는 설정에 따라 다르게 할 수도 있지만 보통은 10개를 기본값으로 설정한다.
그래서 이미 서버가 띄워질 때에 커넥션 10개 정도의 커넥션이 있기 때문에 애플리케이션 로직에서는 커넥션을 요청할 때에 바로 커넥션 풀에 요청을 하면 된다. (미리 생성된 객체를 참조하는 방식으로 가져와서 사용한다.)
그리고 JDBC 표준 인터페이스를 통해 DB드라이버로 커넥션을 얻어서 로직을 수행한 뒤 리소스를 정리하는 경우는 리소스를 완전히 종료하여서 메모리 누수를 막으려 했다. 하지만 이렇게 해버리면 커넥션 풀을 사용하는 목적에 맞지 않다.
즉, 리소스를 정리하는 것이 아닌 다시 커넥션 풀에 반환하여 다음 연결 시 커넥션이 필요한 요청에 대해서 빠르게 다시 커넥션 연결을 맺고 DB를 사용할 수 있도록 종료가 아닌 반납을 해야한다!!
커넥션 풀에 대한 전반적인 개념은 이렇다. 실무에서 거의 기본적으로 사용한다고 하여 추가적인 개념들을 정리해보자면
- 대부분 오픈 소스를 사용하는데 HikariCP가 스프링에서 기본적으로 제공을 해주어서 이 커넥션 풀 라이브러리를 사용한다고 생각하면 된다.
데이터 소스
커넥션을 얻는 방법
- JdbcDriverManager를 통해 직접 커넥션 연결을 얻거나
- 커넥션 풀을 통해 커넥션을 얻는 방법
앞서 Jdbc로 개발한 로직을 커넥션 풀을 사용하는 방법으로 변경하려면 어플리케이션 로직의 코드가 변경이 생긴다.
결국 사용하는 코드가 달라서 코드의 변경이 불가피하고 이 과정에서 오류가 발생할 가능성이 높다. 그래서 이 커넥션을 얻는 방법 자체를 추상화를 하여(인터페이스로 만들어) 사용한다면 애플리케이션 로직에는 커넥션을 얻는 사용 로직만 존재하게 되어 방식을 변경하더라도 애플리케이션의 변경을 줄일 수 있다.
이를 가능하게 해주는 것이 데이터 소스 인터페이스의 역할이다.
**DataSource → 커넥션 얻는 다양한 방식들을 통합해준 고마운 분..!(인터페이스) 이렇게 이해하자!**
결국 커넥션을 얻는 다양한 방식을 통합해주는 것이 목적이기 때문에 핵심 기능은 getConnection() 하나이다.
다른 기능도 좀 있다고는 한다.
DriverManager는 DataSource 인터페이스를 사용하지 않는다. DriverManager는 직접 사용해야한다고 한다.
하지만 또 고마운 스프링께서 DriverManagerDataSource라는 DataSource 구현 클래스를 제공해준 덕분에 이를 사용하면 된다..ㅎㅎ
실습 해보자
DriverManager를 통해 커넥션 연결을 얻어와 조회해보면 두 커넥션이 모두 다른 것을 알 수 있다.
커넥션 풀로 변경했을 때 사용하기 위한 DriverManagerDataSource 를 사용한 커넥션 연결 역시 커넥션 요청을 할 때마다 새로운 연결 요청을 하는 것을 볼 수 있었다.
(테스트 코드)
@Test
void driverManager() throws SQLException {
Connection con1 = DriverManager.getConnection(URL, USERNAME, PASSWORD);
Connection con2 = DriverManager.getConnection(URL, USERNAME, PASSWORD);
log.info("con1={}, class={}", con1, con1.getClass());
log.info("con2={}, class={}", con2, con2.getClass());
}
@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("con1={}, class={}", con1, con1.getClass());
log.info("con2={}, class={}", con2, con2.getClass());
}
DriverManager와 DriverManagerDataSource의 차이점을 알 수 있는데 DriverManager의 경우 매번 커넥션을 요청할 때마다 연결 정보를 넘겨주어야 하는 반복이 일어나는 반면 DriverManagerDataSource의 경우는 한번 정보를 넘겨주면 그 다음은 커넥션을 얻기위한 메서드인 getConnection()을 호출만 하면 된다.
이는 설정과 사용의 분리에 관한 중요한 차이를 불러온다.
설정에 있어서 이점을 알아보자.
DataSource를 사용하는 부분의 처음 연결정보를 넘기는, 설정과 관련된 부분을 한 곳으로 몰아 놓으면 이후 변경이 발생하였을 때 전체 코드를 변경해야하는 번거로움을 줄일 수 있다.
사용하는 데 있어서는 이미 한 곳에서 설정을 해준 상태이기 때문에 사용에 집중할 수 가 있다.
정리하자면 코드가 여러군데에 지저분하게 퍼지지 않고 한 곳에서 관리될 수 있다는 특징이 생긴다. 언제? DataSource를 사용함으로서 설정과 사용의 분리를 할 경우!
커넥션 풀을 통해 커넥션을 얻어오는 테스트도 진행해보자
@Test
void dataSourceConnectionPool() throws SQLException, InterruptedException {
HikariDataSource dataSource = new HikariDataSource();
dataSource.setJdbcUrl(URL);
dataSource.setUsername(USERNAME);
dataSource.setPassword(PASSWORD);
dataSource.setMaximumPoolSize(10);
dataSource.setPoolName("MyConnectionPool");
useDataSource(dataSource);
Thread.sleep(1500);
}
HikariDataSource: HikariCP 커넥션 풀을 사용하여 데이터 소스를 얻어올 수 있다. 해당 객체는 DataSource 인터페이스를 구현하고 있다.
얻어온 데이터 소스를 통해 db커넥션을 얻기 위해 연결 정보를 넘기는데 조금 특이한 부분은 풀 이름을 설정할 수 있고, 최대 풀의 크기까지 설정할 수 있다.
Thread.sleep()은 실습 시 커넥션이 너무 빨리 생성 되어 로그 확인이 되지 않는 부분을 찍을 수 있도록 약간의 딜레이를 주었다. 그래도 로그가 확인되지 않는다면 로그를 띄울 수 있는 방법은 구글링을 해보면 금방 찾을 수 있다!
(로그 띄우는 방법까지 쓰는게 글의 목적과 쪼금 달라서 일부러 넣지 않았습니다!)
- hikariCP를 통해 커넥션 풀에 커넥션들을 을 가져오기 위해 데이터 소스를 생성하고 데이터 소스에 설정 정보를 넘겨 주었다.
- 커넥션 풀을 10개를 생성하면서 테스트에서 2개의 커넥션을 등록하는 것을 확인할 수 있었다.
- MyConnectionPool connection adder라는 별도의 스레드를 사용한다. 그 이유는 커넥션 풀에 커넥션을 채우는 행위 자체가 시간이 상대적으로 오래 걸리는 일이기 때문에 애플리케이션 실행 시간에 영향을 주지 않기 위해서 별도의 스레드를 사용하여 커넥션 풀을 생성한다.
git-hub 실습 코드
'springboot > DB' 카테고리의 다른 글
@Lob의 사용, tinytext?, text?, varchar? 무엇을 사용할까..!? (0) | 2024.05.29 |
---|---|
MySQL 스프링 부트에 연동 해보기 (2) 커넥션 생성 해보기, 스프링부트 연결하기 (2) | 2024.05.14 |
MySQL 스프링 부트에 연동 해보기 (1) MySQL 완전히 삭제 후 재 설치하기 (0) | 2024.05.13 |
MySQL server 설치 후 서버 실행 오류 (0) | 2024.05.11 |
JDBC 실습 해보기 (2) | 2024.02.09 |