이 글은 김영한님의 스프링 DB 1편 강의중 제목과 관련된 부분을 블로그장 입맛대로 요약한 것이며 강의 자료 및 출처는 가장 아래에서 확인할 수 있습니다.
1. JDBC란?
JDBC(Java Database Connectivity)는 자바에서 데이터베이스에 접속할 수 있도록 하는 자바 API이다.
등장배경
위는 애플리케이션 서버가 일반적으로 DB와 통신하는 것을 나타낸 그림이다.
만약, 위 상태에서 MySQLDB가 아닌 OracleDB로 변경되면 어떻게 될까?
커넥션 연결, SQL 전달, 결과를 응답하는 방법은 모든 DB마다 다르기때문에 데이터베이스 관련 코드를 모두 변경해야 할것이다.
따라서 JDBC 표준 인터페이스를 제공하게 되면서 각 DB 벤더(회사)에서 인터페이스에 맞도록 구현하여 라이브러리로 제공하게 되었다. 이때 이 라이브러리를 JDBC 드라이버라고 한다.
이제 애플리케이션 로직은 JDBC 표준 인터페이스만 의존하면 되고, 다른 DB로 변경시 JDBC 구현 라이브러리만 변경하면 된다.
2. SQL Mapper, ORM이란?
SQL Mapper는 말그대로 개발자가 직접 작성한 SQL문과 객체 필드를 매핑하여 데이터를 객체화 해주는 프레임 워크이며ORM은 객체를 관계형 데이터베이스 테이블과 매핑해주는 기술이다.
등장배경
JDBC는 오래된 기술이기에 사용하는 방법이 복잡하다.
따라서 이를 편리하게 사용하게 하는 다양한 기술이 존재하는데 그 중 대표적으로 SQL Mapper와 ORM이 있다.
SQL Mapper 특징
개발자가 SQL을 직접 작성해야 하는 대신, JDBC반복 코드를 제거해주고 응답 결과를 객체로 편리하게 변환해준다.
대표적으로 스프링 JdbcTemplate과 Mybatis가 있다.
ORM 기술 특징
개발자는 SQL을 직접 작성하지 않고, 개발자 대신 SQL을 동적으로 만들어 실행해준다.
대표적으로 JPA, 하이버네이트, 이클립스링크등이 있다.
추가로 설명하자면 JPA는 자바 진영의 ORM 표준 인터페이스이고, 이것을 구현한 것이 하이버네이트와 이클립스 링크이다.
3. 커넥션풀이란?
커넥션 풀은 이름그대로 커넥션을 관리하는 풀로, 커넥션을 미리 생성해두고 사용하는 방법이다.
등장배경
데이터베이스 커넥션을 획득할 때는 아래와 같이 복잡한 과정을 거친다.
커넥션을 획득할 때는 애플리케이션 서버에서 TCP/IP 연결을 위한 네트워크 동작이 발생하는등 복잡하고 시간이 많이 소요된다. 실제로 고객이 이용할때 SQL실행 시간 뿐만 아니라 커넥션을 새로 만드는 시간이 추가되기 때문에 응답속도에 영향을 준다.
따라서 커넥션을 미리 생성해두고 사용하는 방법인 커넥션 풀이 등장하게 된다.
특징
서버당 최대 커넥션 수를 제한할 수 있으므로, DB의 무한정 연결 생성을 방지할 수 있다. 이점이 매우 크기때문에 실무에선 항상 기본으로 사용한다.
대표적인 오픈소스로 commons-dbcp2, tomcat-jdbc pool, hikariCP등이 있는데 스프링부트 2.0부턴 기본적으로 hikariCP를 제공한다. 다방면에서 안정적으로 검증되었기 때문에 실무에서도 대부분 hikariCP를 사용한다.
4. DataSource란?
DataSource는 자바에서 제공하는 커넥션을 획득하는 방법을 추상화하는 인터페이스이다.
등장배경
커넥션을 얻는 방법은 다양한데, DriverManager를 직접 사용하거나 커넥션 풀을 사용하는 등 다양한 방법이 존재한다.
만약 커넥션을 얻기 위해 처음에 DriverManager를 사용하다가 커넥션 풀을 사용하는 방식으로 변경하게 되면, 어플리케이션에서 관련 코드 변경이 필요할 것이다. 의존관계가 변경되고, 사용법도 조금씩 다를것이므로 코드 수정이 크게 일어날것이다.
따라서 커넥션 획득을 추상화하여 사용하게 되었다.
예제
아래 코드를 살펴보자
@Slf4j
public class ConnectionTest {
@Test
void dataSourceDriverManager() throws SQLException{
//DriverManagerDataSource - 항상 새로운 커넥션 획득
DriverManagerDataSource dataSource = new DriverManagerDataSource(URL, USERNAME, PASSWORD);
useDataSource(dataSource);
}
/**
* 커넥션 풀에서 커넥션을 생성하는 작업은 애플리케이션 실행 속도에 영향을 주지 않기 위해 별도의 쓰레드에서 작동한다.
* 별도의 쓰레드에서 동작하기 때문에 테스트가 먼저 종료되어 버린다. 따라서 Thread.sleep 처럼 대기 시간을 주어야 쓰레드 풀에 커넥션이 생성되는 로그를 확인할 수 있다.
*/
@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(9000); // 커넥션 풀에서 커넥션 생성 시간 대기
}
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());
}
}
첫번째 테스트는 DriverManagerDataSource를 사용하며, 두번째 테스트는 HikariDataSource를 사용한다.
실제로 커넥션을 획득하는 부분은 useDataSource()인데 단지 파라미터로 dataSource만 넘겨서 사용하면 되기 때문에 편리해졌다.
따라서 실제로 구현한다면 repository는 DataSource만 의존하고, DataSource는 설정과 관련된 속성이 모여있는곳에 두면 깔끔하게 구현될것이다.(DI + OCP)
* 출처 자료
https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-db-1
'Spring' 카테고리의 다른 글
Spring DB 정리 3) 트랜잭션AOP 주의사항과 예외 처리 (0) | 2024.03.06 |
---|---|
Spring DB 정리 2) 트랜잭션 처리 및 예외 처리 (0) | 2024.02.13 |
Spring MVC 정리 4) 예외 처리 (0) | 2023.12.18 |
Spring MVC 정리 3) 검증 (0) | 2023.11.06 |
Spring MVC 정리 2)단계별로 구현하며 알아보는 스프링의 핵심 기술 (0) | 2023.10.25 |