Notice
Recent Posts
Recent Comments
Link
«   2025/05   »
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 31
Archives
Today
Total
관리 메뉴

Develog

코드스테이츠 46일차 본문

코드스테이츠

코드스테이츠 46일차

안형준 2022. 6. 30. 18:17

학습 목표

  • JDBC가 무엇인지 이해할 수 있다.
  • Spring Data JDBC가 무엇인지 이해할 수 있다.
  • Java에서 JDBC가 어떤 역할을 하는지 이해할 수 있다.
  • Spring Data JDBC를 이용해서 데이터의 저장, 수정, 조회, 삭제 작업을 할 수 있다.
  • Spring Data JDBC 기반의 엔티티 연관 관계를 매핑할 수 있다.

 

JDBC란?

JDBC(Java Database Connectivity)는 Java 기반 애플리케이션의 코드 레벨에서 사용하는 데이터를 데이터베이스에 저장 및 업데이트 하거나 반대로 데이터베이스에 저장된 데이터를 Java 코드 레벨에서 사용할 수 있도록 해주는 Java에서 제공하는 표준 API이다.

JDBC는 Java 초창기(JDK 1.1) 버전부터 제공되는 데이터베이스 액세스 기능을 위한 API이며, Java 개발자는 JDBC API를 사용해서 다양한 벤더(Oracle, MS SQL, MySQL 등)의 데이터베이스와 연동할 수 있다.

 

JDBC는 Java 기반의 애플리케이션에서 사용하는 데이터 액세스 기술의 기본이 되는 저수준(low level) API이다.

또한 Spring에서는 JDBC API를 직접적으로 사용하기 보다는 Spring Data JDBC나 Spring Data JPA 같은 기술을 제공함으로써 개발자들이 조금 더 편리하게 데이터 액세스 로직을 구현할 수 있도록 해준다.

다만, JDBC의 동작 흐름 정도는 기억하자

 

JDBC의 동작 흐름

JDBC의 동작 흐름

JDBC는 Java 애플리케이션 내에서 JDBC API를 사용하여 데이터베이스에 액세스하는 단순한 구조이기때문에 JDBC의 동작 흐름은 매우 간단하다.

JDBC API를 사용하기 위해서는 JDBC 드라이버를 먼저 로딩한 후에 데이터베이스와 연결하게 된다.

 

JDBC 드라이버(JDBC Driver)

JDBC 드라이버는 데이터베이스와의 통신을 담당하는 인터페이스인데, Oracle이나 MS SQL, MySQL 같은 다양한 벤더에서는 해당 벤더에 맞는 JDBC 드라이버를 구현해서 제공을 하게되고, 우리는 이 JDBC 드라이버의 구현체를 이용해서 특정 벤더의 데이터베이스에 액세스 할 수 있다.

 

JDBC API 사용 흐름

  • 1. JDBC 드라이버 로딩

사용하고자 하는 JDBC 드라이버를 로딩한다. JDBC 드라이버는 DriverManager라는 클래스를 통해서 로딩된다.

 

  • 2. Connection 객체 생성

JDBC 드라이버가 정상적으로 로딩되면 DriverManager를 통해 데이터베이스와 연결되는 세션(Session)인 Connection 객체를 생성한다.

 

  • 3. Statement 객체 생성

Statement 객체는 작성된 SQL 쿼리문을 실행하기 위한 객체로써 객체 생성 후에 정적인 SQL 쿼리 문자열을 입력으로 가진다.

 

  • 4. Query 실행

생성된 Statement 객체를 이용해서 입력한 SQL 쿼리를 실행한다.

 

  • 5. ResultSet 객체로부터 데이터 조회

실행된 SQL 쿼리문에 대한 결과 데이터 셋이다.

 

  • 6. ResultSet 객체 Close, Statement 객체 Close, Connection 객체 Close

JDBC API를 통해 사용된 객체들은 사용 이후에 사용한 순서의 역순으로 차례로 Close를 해주어야한다.

 

 

Connection Pool이란?

Connection Pool 사용 흐름

JDBC API를 사용해서 데이터베이스와의 연결을 위한 Connection 객체를 생성하는 작업은 비용이 많이 드는 작업 중 하나이기 떄문에 애플리케이션 로딩 시점에 Connection 객체를 미리 생성해두고 애플리케이션에서 데이터베이스에 연결이 필요할 경우, Connection 객체를 새로 생성하는 것이 아니라 미리 만들어 둔 Connection 객체를 사용함으로써 애플리케이션의 성능을 향상 시킬 수 있다.

이처럼 데이터베이스 Connection을 미리 만들어서 보관하고 애플리케이션이 필요할 때 이 Connection을 제공해주는 역할을 하는 Connection 관리자를 바로 Connection Pool이라 한다.

 

총정리

  • JDBC(Java Database Connectivity)는 Java 기반 애플리케이션의 코드 레벨에서 사용하는 데이터를 데이터베이스에 저장 및 업데이트 하거나 반대로 데이터베이스에 저장된 데이터를 Java 코드 레벨에서 사용할 수 있도록 해주는 Java에서 제공하는 표준 API이다.
  • JDBC의 구체적인 API 사용법을 알 필요는 없지만 JDBC의 동작 흐름을 알면 Spring에서 지원하는 데이터 액세스 기술을 사용하는데 도움이 된다.
  • 데이터베이스 Connection 객체를 미리 만들어서 보관하고 애플리케이션이 필요할 때 이 Connection을 제공해주는 역할을 하는 Connection 관리자를 바로 Connection Pool이라고 한다.
  • Spring Boot 2.0부터 HikariCP가 기본 DBCP로 채택되었다.

 

Spring Data JDBC란?

Spring에는 mybatis, Spring JDBC, Spring Data JDBC, JPA, Spring Data JPA 등 다양한 데이터 엑서스 기술이 있다.

 

SQL 중심 기술

mybatisSpring JDBC는 대표적인 SQL 중심 기술이다.

즉, SQL 중심 기술은 애플리케이션에서 데이터베이스에 접근하기 위해 SQL 쿼리문을 애플리케이션 내부에 직접적으로 작성하는 것이 중심이 되는 기술이다.

Ex)

<select id="findMember" resultType="Member">

  SELECT * FROM MEMBER WHERE member_id = #{memberId}

</select>

 

mybatis의 경우, SQL Mapper라는 설정 파일이 존재하는데 이 SQL Mapper에서 SQL 쿼리문을 직접적으로 작성한다.

작성된 SQL 쿼리문을 기반으로 데이터베이스의 특정 테이블에서 데이터를 조회한 후, Java 객체로 변환해 주는 것이 mybatis의 대표적인 기술적 특징이다.

하지만 현 시점의 Java 진영에서는 SQL 중심의 기술에서 객체(Object) 중심의 기술로 지속적으로 이전을 하고 있는 추세라는 사실을 기억해두자

 

객체(Object) 중심 기술

객체(Object) 중심 기술은 데이터를 SQL 쿼리문 위주로 생각하는 것이 아니라 모든 데이터를 객체(Object) 관점으로 바라보는 기술이다.

즉, 객체(Object) 중심 기술은 데이터베이스에 접근하기 위해서 SQL 쿼리문을 직접적으로 작성하기 보다는 데이터베이스의 테이블에 데이터를 저장하거나 조회할 경우, Java 객체(Object)를 이용해 애플리케이션 내부에서 이 Java 객체(Object)를 SQL 쿼리문으로 자동 변환 한 후에 데이터베이스의 테이블에 접근한다.

이러한 객체(Object) 중심의 데이터 액세스 기술을 ORM(Object-Relational Mapping)이라고 한다.

대표적인 ORM 기술이 바로 JPA(Java Persistence API)이고, JPA를 사용하면 여러분들이 SQL 쿼리문을 직접적으로 다룰 일이 적어진다.

물론 복잡한 조건의 데이터 조회를 위해 SQL 쿼리문을 사용하기도하지만 사용 빈도수는 이 전보다 급격히 줄어들 것이다.

 

그렇다면 Spring Data JDBC란 무엇일까?

Spring Data JDBC는 JPA처럼 ORM 기술을 사용하지만 JPA의 기술적 복잡도를 낮춘 기술이라고 볼 수 있다.

 

Spring Data JDBC vs JPA vs Spring Data JPA

Spring Data JDBC 기술은 2018년에 1.0 버전이 처음 릴리즈 되었기 때문에 기술의 역사가 아직 짧은 편이다.

현재도 기능 업그레이드가 꾸준히 이루어지고 있지만 아직까지는 JPA보다 상대적으로 적게 사용되고 있다.

하지만 애플리케이션의 규모가 상대적으로 크지 않고, 복잡하지 않을 경우에는 Spring Data JDBC가 뛰어난 생산성을 보여줄 수 있다.

JPA와 Spring Data JPA를 이해하는데 꽤 많은 도움이 되기 때문에 Spring Data JPA 학습을 꼭 해야한다.

 

JPA 는 실무에서 가장 많이 사용하고 있는 기술이다.

 

Spring Data JPA는 Spring에서 JPA 기술을 편리하게 사용하기 위한 기술이기 때문에 JPA에 대한 선행 지식이 있어야 제대로 사용할 수 있다.

 

Spring Data JDBC를 사용하기 위한 사전 준비 (간단한 샘플 코드로 이해 해보기)

의존 라이브러리 추가

Spring Data JDBC를 사용하기 위해서는 build.gradle의 dependencies에 Spring Boot Starter를 추가해야한다.

dependencies {

...

...

implementation 'org.springframework.boot:spring-boot-starter-data-jdbc'

runtimeOnly 'com.h2database:h2'

}

위 코드는 인메모리(In-memory) DBH2를 사용하기 위해 의존 라이브러리 설정에 추가했는데

여기서 인메모리(In-memory) DB란 무엇일까?

일반적으로 우리가 알고 있는 데이터베이스는 삭제를 하지 않는 이상 데이터베이스 서버를 내렸다가 다시 가동시켜도 데이터베이스 안에 데이터가 그대로 유지되지만 인메모리(In-memory) DB는 메모리의 휘발성 때문에 컴퓨터 전원을 내렸다가 다시 올리면 메모리에 저장되어 있는 데이터는 모두 지워지게 된다.

이처럼 인메모리(In-memory) DB는 애플리케이션이 실행되는 동안에만 데이터를 저장하고 있기 때문에 애플리케이션 실행을 중지했다가 다시 실행시키면 인메모리(In-memory) DB안에 저장되어 있던 데이터는 모두 사라지게 된다.

 

그럼 인메모리(In-memory) DB는 왜 사용할까?

실제 운영 운영 환경에서는 당연히 인메모리(In-memory) DB를 사용하면 안된다.

하지만 개발을 할 때 인메모리(In-memory) DB는 테스트 측면에서 많은 이점을 가진다.

물론 Spring에서 지원하는 테스트 기능에서는 테스트가 끝나면 테스트에 사용한 데이터를 자동으로 지워주는 기능이 있지만 기본적으로 로컬 테스트 환경에서는 인메모리(In-memory) DB 사용을 권장한다라는 사실을 기억하자

 

application.yml 파일에 H2 Browser 활성화 설정 추가

이제 src/main/resources’ 디렉토리 하단에 application.properties 라는 비어 있는 파일이 보일 것이다.

Spring에서는 application.properties 또는 application.yml 파일을 통해 Spring에서 사용하는 다양한 설정 정보들을 입력할 수 있다.

.yml 파일은 애플리케이션의 설정 정보(프로퍼티)를 depth 별로 입력할 수 있는 더 나은 방법을 제공하기 때문에 application.properties 의 파일 확장자를 application.yml로 변경해두자 (단축키 Shift + F6)

그리고 그 코드에 H2 관련 설정을 추가한다면

spring:

  h2:

    console:

      enabled: true

웹 브라우저 상(H2 콘솔)에서 H2 DB에 접속한 후, 데이터베이스를 관리할 수 있게된다.

.yml(또는 yaml) 파일에 indent를 주어서 depth를 설정할 때에는 스페이스 바를 눌러서 indent를 설정해도 상관없지만 일반적으로는 Tab(탭) 키를 사용해서 일관성을 유지하는 것이 좋다.

 

H2 DB 정상 동작 유무 확인

 

H2 DB 디폴트 설정의 문제점

H2 DB는 애플리케이션을 재시작 할때 마다 애플리케이션 로그에 출력되는 JDBC URL이 매번 랜덤하게 바뀌기 때문에 매번 랜덤하게 변경된 JDBC URL을 다시 입력하는 것은 상당히 불편할 수 있다.

이 문제는 application.yml 파일에 H2에 대한 추가 설정을 함으로써 해결할 수 있다.

 

H2 DB 설정 추가

spring:

  h2:

    console:

      enabled: true

      path: /h2     # (1) Context path 변경

  datasource:

    url: jdbc:h2:mem:test     # (2) JDBC URL 변경

이제 애플리케이션을 재가동 시키고, ‘localhost:8080/h2’로 접속한 뒤 [JDBC URL] 항목에 ‘jdbc:h2:mem:test’을 입력하고 [Connect] 버튼을 클릭하면 정상적으로 접속될 것이다.

Spring Boot에서는 appliation.properties 또는 application.yml 파일을 통해 굉장히 많은 설정 정보를 추가할 수 있다.

 

코드 구현(DTO, Controller등)

 

데이터 액세스 계층에서 데이터베이스와의 연동을 담당하는 Repository인 MessageRepository 인터페이스를 만들어야하는데

import org.springframework.data.repository.CrudRepository;



public interface MessageRepository extends CrudRepository<Message, Long> {

}

위와 같이 인터페이스 내부에는 단 한줄의 코드도 없는 점을 확인할 수 있다.

특이한 것은 CrudRepository라는 인터페이스를 상속하고 있고, 이 CrudRepository의 제너릭 타입이 <Message, Long>으로 선언되어 있다.

CrudRepository 는 데이터베이스에 CRUD(데이터 생성, 조회, 수정, 삭제) 작업을 진행하기 위해 Spring에서 지원해주는 인터페이스이다.

CrudRepository<Message, Long> 와 같이 제너릭 타입을 지정해줌으로써 Message 엔티티 클래스 객체에 담긴 데이터를 데이터베이스 테이블에 생성 또는 수정하거나 데이터베이스에서 조회한 데이터를 Message 엔티티 클래스로 변환할 수 있다.

<Message, Long>에서 Long은 Message 엔티티 클래스의 멤버 변수 중에 식별자를 의미하는 @Id 라는 애너테이션이 붙어있는 멤버 변수의 데이터 타입이다.

짧은 한줄 짜리 MessageRepository 인터페이스 내부에 아무런 코드도 없지만 우리는 이 MessageRepository 인터페이스를 서비스 계층에서 DI를 통해 주입받은 후, 데이터베이스 작업을 위해 사용하게된다.

 

H2 DB에 MESSAGE 테이블 생성

spring:

  h2:

    console:

      enabled: true

      path: /h2     

  datasource:

    url: jdbc:h2:mem:test

  sql:

    init:

      schema-locations: classpath*:db/h2/schema.sql   // (1) 테이블 생성 파일 경로

Spring 에서는 (1)과 같이 테이블 생성을 위한 SQL 문이 추가된 ‘schema’라는 파일명으로 .sql 파일의 경로를 지정해주면 이 schema.sql 파일에 있는 스크립트를 읽어서 애플리케이션 실행 시, 데이터베이스에 테이블을 자동으로 생성해준다.

그리고 인메모리 DB를 사용할 경우, 애플리케이션이 실행될 때 마다 schema.sql 파일의 스크립트가 매번 실행된다는 사실 또한 기억하자

‘schema.sql’ 파일은 ‘src/main/resources/db/h2’ 디렉토리내에 위치해있다.

 

schema.sql에 정의된 테이블 생성 스크립트

CREATE TABLE IF NOT EXISTS MESSAGE (

    message_id bigint NOT NULL AUTO_INCREMENT,

    message varchar(100) NOT NULL,

    PRIMARY KEY (message_id)

);

‘message_id’는 MESSAGE 테이블의 Primary key이고 AUTO_INCREMENT를 지정했기 때문에 데이터가 insert 될때 마다 자동으로 증가되므로 애플리케이션 쪽에서 직접 데이터에 해당하는 값을 지정해주지 않아도 된다.

 

MESSAGE 테이블은 Message 클래스 명과 매핑되고 ‘message_id’ 컬럼은 Message 클래스의 messageId 멤버 변수와 매핑된다.

‘message’ 컬럼은 Message 클래스의 message 멤버 변수와 매핑된다.

 

ORM(Object-Relational Mapping)에서는 객체의 멤버 변수와 데이터베이스 테이블의 컬럼이 대부분 1대1로 매핑이 된다는 점 꼭 기억하자

 

실행화면

요청 전송 시, Request Body에 messageId 값은 포함하지 않았는데, Response Body에는 messageId가 포함이 되어있다.

MESSAGE 테이블의 식별자(Primary key)인 ‘message_id’ 컬럼에 AUTO_INCREMENT 설정이 되어 있으므로 ‘message_id’ 컬럼에 값을 입력하지 않더라도 데이터가 저장이 될 때 마다 자동으로 포함이 되는 점 기억해두자

 

Spring Data JDBC 적용 순서 정리

  1. build.gradle에 사용할 데이터베이스를 위한 의존 라이브러리를 추가한다.
  2. application.yml 파일에 사용할 데이터베이스에 대한 설정을 한다.
  3. ‘schema.sql’ 파일에 필요한 테이블 스크립트를 작성한다.
  4. application.yml 파일에서 ‘schema.sql’ 파일을 읽어서 테이블을 생성할 수 있도록 초기화 설정을 추가한다.
  5. 데이터베이스의 테이블과 매핑할 엔티티(Entity) 클래스를 작성합니다.
  6. 작성한 엔티티 클래스를 기반으로 데이터베이스의 작업을 처리할 Repository 인터페이스를 작성한다.
  7. 작성된 Repository 인터페이스를 서비스 클래스에서 사용할 수 있도록 DI 한다.
  8. DI 된 Repository의 메서드를 사용해서 서비스 클래스에서 데이터베이스에 CRUD 작업을 수행한다.

 

총정리

  • 데이터 액세스 기술의 유형은 크게 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 파일의 설정 정보 등록을 통해 데이터베이스 설정, 데이터베이스의 초기화 설정 등의 다양한 설정을 할 수 있다.
  • application.yml 방식은 중복되는 프로퍼티의 입력을 줄여주기 때문에 application.properties 방식보다 더 선호되는 추세이다.
  • 엔티티(Entity) 클래스 이름은 데이터베이스 테이블의 이름에 매핑되고, 엔티티 클래스 각각의 멤버 변수는 데이터베이스 테이블의 컬럼에 매핑된다.
  • 엔티티 클래스의 멤버 변수에 @Id 애너테이션을 추가하면 데이터베이스 테이블의 기본키(Primary key) 컬럼과 매핑된다.

'코드스테이츠' 카테고리의 다른 글

코드스테이츠 48-49일차  (0) 2022.07.04
코드스테이츠 47일차  (0) 2022.07.03
코드스테이츠 45일차  (0) 2022.06.29
코드스테이츠 44일차  (0) 2022.06.28
코드스테이츠 43일차  (2) 2022.06.27