데이터는 영속성이 중요하다. 영속성이란 프로그램이 종료되더라도 사라지지 않는 것을 뜻하며 애플리케이션은 데이터를 영구적으로 저장하기 위해서 JDBC, DataSource, 영속성 프레임워크 등의 기술들을 조합하여 사용한다. 구조를 보면 아래와 같다.

JDBC는 자바를 사용하여 데이터베이스에 접속하고 SQL을 실행하기 위한 Java API 다. JDBC의 구성 요소는 아래와 같다.
JDBC API
java.sql 및 javax.sql 패키지에 포함되어 있다.JDBC Driver
각 데이터베이스 제공 회사가 제공하는 소프트웨어 모듈이다. JDBC API의 인터페이스를 구현하며, 자바 프로그램의 요청(SQL)을 해당 데이터베이스가 이해할 수 있는 네이티브 프로토콜로 변환하여 데이터베이스와 실제로 통신하는 역할을 한다. 보통 ojdbc.jar 과 같이 jar로 제공한다.
jdbc url 에서 사용하는 속성 jdbc:postgresql://localhost/test?user=fred&password=secret&ssl=true 과 같이 option부분은 jdbc의 동작방식을 설정하는 것이다. 드라이버는 ? 뒤에 붙은 옵션들을 파싱하여 자신의 내부 동작 모드를 변경한다. 즉, 이 옵션들은 드라이버 내부에 저장되는 설정 값으로, 이는 각 dbms의 jdbc driver에 따라 다르니 공식문서를 참고해야한다.

JDBC Driver Manager
Connection 객체를 생성하고 반환하는 역할을 한다.Connection
Connection 객체를 통해 이루어지며, SQL 문 실행, 트랜잭션 관리(commit, rollback) 등의 기능을 제공한다. ORM 혹은 스프링의 @transactional 의 경우도 내부적으로는 Connection 객체를 활용하고 있다.Statement
데이터베이스에 SQL 문을 전달하고 실행하는 데 사용되는 인터페이스이다.
Statement 객체를 실제로 생성하고 메서드를 실행하는 것은 JDBC 드라이버의 역할이다.
드라이버의 구현체 사용: Connection 인터페이스를 통해 createStatement()를 호출하면, JDBC 드라이버가 Statement 인터페이스를 구현한 특정 클래스(Statement 구현체)의 인스턴스를 반환한다.
SQL 번역 및 전송: 자바 애플리케이션이 stmt.executeQuery(SQL)를 호출하면, 이 구현체는 인자로 받은 SQL 문자열을 데이터베이스 서버가 이해할 수 있는 네이티브 프로토콜 형태로 변환한다. 이 프로토콜 데이터를 네트워크를 통해 DBMS로 전송한다.
아래의 그림은 실제로 Statement 인터페이스의 구현체가 postgreSql driver의 구현체를 사용하고 있음을 보여준다.

네트워크를 통해 전달받은 SQL 요청은 DBMS의 역할이다.
SELECT * FROM users)을 데이터베이스 엔진에서 실제로 실행하게 된다.JDBC 드라이버에서 해당 SQL을 번역하기 떄문에, DBMS에서 사용하는 문법을 해당 JDBC에 제공하고 있지 않으면 구문을 해석할 수 없기때문에 오류가 난다. 실제로 PostgreSQL의 확장 플러그인으로 $$ 라는 문법을 사용할 일이 있었는데 해당 부분을 처리해주는 JDBC가 기본 PostgreSQL Driver에는 표준 구문으로 인식하기 위한 처리가 존재하지 않는다. 그래서 정적 SQL을 지원하는 Statement 가 아닌 내부적으로 PreparedStatement 를 사용하는 클래스들은 처리과정에서 오류가 발생하게 되는 것을 발견했다.
ResultSet
SELECT와 같은 질의(Query) 결과를 담는 데이터 집합이다. 데이터베이스에서 반환된 테이블 형태의 데이터를 자바 프로그램이 접근하고 처리할 수 있도록 하며, 커서를 이용하여 한 행씩 이동하며 데이터를 읽어온다.
jdbc 실행 순서는 다음과 같다.
커넥션을 가장 기본적으로 사용할때는 Driver Manger를 통해 매번 데이터베이스에 직접 연결을 시도하는데, 이는 연결 요청이 있을때 마다 매번 새 연결을 만들고 닫아야하기 떄문에 시간이 많이 소요된다.
이러한 단점을 극복하기 위해 데이터베이스와 매번 새로운 커넥션을 생성하는 대신 미리 생성된 커넥션을 커넥션 풀에 보관하고 꺼내서 사용하는 방식을 사용한다.
이를 추상화한 DataSource 인터페이스를 통해서 커넥션 연결을한다. 이러한 DataSource의 구현체는 대표적으로 HikariCp, Apache DBCP 등이 있다.
기본 jdbc 를 직접 사용할 경우 개발자는 아래와 같이 일일히 커넥션을 호출하게 된다.
Connection conn = DriverManager.getConnection(url, user, password);
그러나 DataSource를 사용하면 DataSource.getConnection() 요청을 처리할 때, HikariCP와 같은 커넥션 풀 구현체가 가로채서 미리 만들어 둔 연결을 재사용한다.
내부적으로 다시 driverManger를 사용할때는
maximum-pool-size) 한도 내에서 새 연결을 만들어야 할 때의 경우에만 사용된다.
보통은 Connection pool을 이용하기 위해 위의 구현체를 사용하지만 Driver Manger를 기반으로하여 커넥션 풀을 제공하지 않는 DriverManagerDataSource 도 제공하고 있다. 이는 spring 프레임워크에서 제공하고 있는 구현체다.
Spring Boot는 HikariCP를 기본적으로 사용하고 있는데, 이 기본적인 사용은 자동설정과 속성 기반 설정, 표준화된 인터페이스 제공을 통해 구현된다.
DataSource 빈 생성: Spring Boot는 개발자의 코드 없이도 DataSource 인터페이스를 구현한 HikariCP 객체를 생성하고 이를 Spring 컨테이너의 빈(Bean)으로 자동 등록한다.spring.datasource.url 과 같은 설정들을 읽어와 HikariCP에 자동으로 주입하게 된다.[출처]