어떠한 애플리케이션을 제작하더라도 데이터베이스(Data Base, DB)와 같은 데이터 저장소와의 연동은 필수이다.
이번엔 서비스 계층에서 비즈니스 로직을 통해 처리된 데이터를 DB에 저장하고 비즈니스 로직을 처리하기 위해 DB에서 데이터를 조회하는 등의 역할을 수행하는 데이터 액세스 계층에 대한 학습을 해보았다.
JDBC는 Java 기반 애플리케이션 코드 레벨에서 사용하는 데이터를 데이터베이스에 저장 및 업데이트 하거나, 반대로 데이터베이스에 저장된 데이터를 Java 코드 레벨에서 사용할 수 있게 하는 Java에서 제공하는 표준 사양 혹은 명세이다.
Java 개발자는 JDBC API를 사용해서 Oracle, MySQL 등 다양한 벤더의 DB와 연동할 수 있다.
Spring Data JDBC나 Spring Data JPA 같은 기술도 DB와 연동하기 위해 내부적으로 JDBC를 사용한다.
그러므로 JDBC의 동작 흐름 정도만이라도 알고 있다면, Spring에서 지원하는 데이터 액세스 기술을 사용하는데 도움이 될 것이다.
JDBC API를 사용하기 위해서는 먼저 JDBC 드라이버를 로딩한 후 DB와 연결하게 된다.
JDBC Driver(JDBC 드라이버)
JDBC 드라이버는 DB와의 통신을 담당하는 인터페이스다. Oracle 같은 벤더에서는 해당 벤더에 맞는 JDBC 드라이버를 구현해 제공하고, 우리는 JDBC 드라이버의 구현체를 이용해 특정 벤더의 DB에 액세스 할 수 있다.
Java 코드 상에서 JDBC API를 사용하는 일반적인 흐름이다.
JDBC 드라이버 로딩
사용하고자 하는 JDBC 드라이버를 로딩한다. JDBC 드라이버는 DriverManager 클래스를 통해 로딩된다.
Connection 객체 생성
JDBC 드라이버가 정상 로딩되면 DriverManger를 통해 DB와 연결되는 세션인 Connection 객체를 생성한다.
Statement 객체 생성
Statement 객체는 작성된 SQL 쿼리문을 실행하기 위한 객체로, 객체 생성 후에 정적인 SQL 쿼리 문자열을 입력으로 갖는다.
Query 실행
생성된 Statement 객체를 이용해서 입력한 SQL 쿼리를 실행한다.
JDBC API를 사용해서 DB와의 연결을 위해 Connection 객체를 생성하는 작업은 비용이 많이 든다.
애플리케이션 로딩 시점에 Connection 객체를 미리 생성하고 애플리케이션에서 DB에 연결이 필요한 경우, 미리 만들어 둔 Connection 객체를 사용해 애플리케이션 성능을 향상시킬 수 있다.
이처럼 데이터베이스 Connection을 미리 만들어서 보관하고 애플리케이션이 필요할 때 이 Connection을 제공해주는 역할을 하는 Connection 관리자를 바로 Connection Pool이라 한다.
Spring에서 사용 가능한 대표적인 데이터 액세스 기술로는 mybatis, Spring JDBC, Spring Data JDBC, JPA, Spring Data JPA 등이 있다.
mybatis와 Spring JDBC는 대표적인 SQL 중심 기술이다. 즉, SQL 중심 기술은 애플리케이션에서 DB에 접근하기 위해 SQL 쿼리문을 애플리케이션 내부에 직접적으로 작성하는 것이 중심이 되는 기술이다.
Member member = this.jdbcTemplate.queryForObject("select * from member where member_id=?", 1, Member.class);
Spring JDBC의 JdbcTemplate이라는 템플릿 클래스를 사용한 데이터베이스 접근 예시 코드이다.
Java 코드에 SQL 쿼리문이 직접적으로 포함되어 있다.
이처럼 SQL 쿼리문이 직접적으로 포함이 되는 방식은 과거부터 많이 사용하던 방식이며 현재도 사용이 되고 있다.
Java 진영에서는 SQL 중심의 기술에서 객체(Object) 중심의 기술로 지속적으로 이전을 하고 있는 추세임을 기억하자!
객체 중심 기술은 데이터를 SQL 쿼리문 위주로 생각하는 것이 아닌, 모든 데이터를 객체 관점으로 바라보는 것이다.
즉, SQL 쿼리문을 직접 작성하기 보다는 DB 테이블에 데이터를 저장하거나 조회할 경우 Java 객체를 이용해 애플리케이션 내부에서 객체를 SQL 쿼리문으로 자동 변환하여 DB 테이블에 접근한다.
이러한 객체 중심 데이터 액세스 기술을 ORM(Object-Relational Mapping)이라 한다.
Java의 대표적인 ORM 기술이 바로 JPA(Java Persistence API)이다.
Spring Data JDBC는 JPA처럼 ORM 기술을 사용하지만 JPA의 기술적 복잡도를 낮춘 기술이다.
Spring Data JDBC vs JPA vs Spring Data JPA
Spring Data JDBC 기술은 2018년에 처음 릴리즈 되어 기술의 역사가 짧아, 현재도 기능 업그레이드가 꾸준히 이루어지고 있다. 애플리케이션의 규모가 상대적으로 작고 복잡하지 않다면 Spring Data JDBC가 뛰어난 생산성을 보여줄 수 있을 것이다.
JPA 는 실무에서 가장 많이 사용하고 있는 기술이다.
Spring Data JPA는 Spring에서 JPA 기술을 편리하게 사용하기 위한 기술로, JPA에 대한 선행 지식이 필요하다.
dependencies {
...
...
implementation 'org.springframework.boot:spring-boot-starter-data-jdbc'
runtimeOnly 'com.h2database:h2'
}
Spring Data JDBC를 사용하기 위해 build.gradle
에 spring-boot-starter-data-jdbc
를 추가한다.
그리고 DB에서 데이터를 관리할 것이기 때문에 인메모리(In-memory) DB인 H2를 사용하기 위해 의존 라이브러리 설정에 추가한다.
인메모리(In-memory) DB
일반적인 DB는 삭제를 하지 않는 이상 DB 서버를 내렸다가 다시 가동시켜도 데이터가 그대로 유지된다.
반면에 인메모리 DB는 메모리 안에 데이터를 저장하는 DB이다. 메모리는 휘발성이기 때문에 PC의 전원을 내렸다가 다시 올리면 메모리에 저장된 데이터를 모두 지워진다.
즉, 인메모리 DB는 애플리케이션이 실행되는 동안에만 데이터를 저장하고 있어, 애플리케이션 실행을 중지했다가 다시 실행시키면 저장되어 있던 데이터는 모두 사라진다.
인메모리(In-memory) DB를 사용하는 이유
운영 환경에서는 인메모리 DB를 사용하지 않고 사용해서도 안 된다. 운영 환경에서의 데이터는 절대 지워지면 안되기 때문이다.
하지만, 개인 PC에서 개발을 하는 경우 인메모리 DB를 사용하는 것이 애플리케이션의 테스트 측면에서 이점이 있다.
테스트를 진행하기 위해서는 테스트에 필요한 데이터 이외에 데이터는 테이블에 없는 것이 정확도 면에서 유리하다. 그러므로 로컬 개발 환경에서는 테스트가 끝나고 나면 DB 테이블에 남아있는 데이터는 깨끗하게 비워져 있는 것이 좋다.
이러한 이유로 로컬 개발 환경에서는 인메모리 DB를 주로 사용한다.
데이터 액세스 기술의 유형은 크게 SQL 중심의 기술과 객체(Object) 중심의 기술로 나눌 수 있다.
SQL 중심의 기술에는 mybatis, Spring JDBC 등이 있다.
객체(Object) 중심의 기술에는 JPA, Spring Data JDBC 등이 있다.
JPA 같은 객체(Object) 중심의 기술을 ORM(Object-Relational Mapping) 기술이라고 한다.
인메모리(In-memory) DB는 애플리케이션이 실행된 상태에서만 데이터를 저장하고 애플리케이션 실행이 중지되면 인메모리 DB 역시 실행이 중지되어 저장된 데이터가 사라진다.
Spring에서 지원하는 CrudRepository
인터페이스는 CRUD에 대한 기본적인 메서드를 정의하고 있어, 별도의 CRUD 기능을 개발자가 직접 구현할 필요가 없다.
application.properties
또는 application.yml
파일의 설정 정보 등록을 통해 DB 설정, DB 초기화 설정 등의 다양한 설정을 할 수 있다.
application.yml
방식은 중복되는 프로퍼티의 입력을 줄여주기 때문에 application.properties
방식보다 더 선호되고 있다.
Entity 클래스 이름은 DB 테이블의 이름에 매핑되고, 엔티티 클래스 각각의 멤버 변수는 DB 테이블의 컬럼에 매핑된다.
Entity 클래스의 멤버 변수에 @Id
애너테이션을 추가하면 DB 테이블의 기본키(Primary key) 컬럼과 매핑된다.