관리 메뉴

제뉴어리의 모든것

[Section3] [Spring MVC] JDBC 기반 데이터 액세스 계층 - 1 본문

코드스테이츠/정리 블로깅

[Section3] [Spring MVC] JDBC 기반 데이터 액세스 계층 - 1

제뉴어리맨 2022. 8. 27. 01:08

JDBC란?

자바 코드상의 데이터를 DB에 저장, 조회, 삭제 하거나 반대로 DB상의 데이터를 자바상의 데이터로 사용할 수 있게 해주는 JAVA에서 제공하는 표준 스펙. 

스펙이라함은 그냥 인터페이스이다.

우리 일상생활에서 내 스펙은 이렇다 저 사람 스펙은 이렇다 말할때의 의미는 어느정도의 능력을 갖췄다란 의미로 쓰인다.

즉, JAVA에서 DB를 사용하기 위해 이런 이런 메소드들은 갖춰라란 것을 스펙이라 한다고 생각하자.

그리고 이러이러한 메소드들을 갖춰라라고 선언만 해주는것이 결국 인터페이스이다.

 

JDBC의 동작 흐름

 

JDBC 드라이버(JDBC Driver)

JDBC 드라이버는 데이터베이스와의 통신을 담당하는 인터페이스.

Oracle이나 MS SQL, MySQL 같은 벤더에서 드라이버의 구현체를 만들어서 제공하면, 개발자는 이러한 구현체를 이용하여 DB접근 기술을 사용하면 된다.

 

JDBC API 사용 흐름

  1. JDBC 드라이버 로딩
    사용하고자 하는 JDBC 드라이버를 로딩합니다. JDBC 드라이버는 DriverManager라는 클래스를 통해서 로딩됩니다.

  2. Connection 객체 생성
    DBC 드라이버가 정상적으로 로딩되면 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이란?

DB를 사용하기 위해선 DB와의 연결상태를 유지하고 있는 Connection이라는 객체가 필요하다.

그런데 이러한 Connection은 최초에 생성하면서 DB와의 Connection을 연결하기 위한 일련의 작업과정이 필요하다.

DB에 뭔가 작업을 할때마다 Connection 객체를 생성하기 위해 이러한 일련의 과정을 수행하면서 지연되는 시간과 리소스를 줄이기 위하여 Connection 객체를 일정량 미리 만들고 관리하는 것이 Connection Pool이라고 한다.

현재 스프링부트 2.0 이후부터는 HikariCP 라는 ConnectionPool을 사용한다.

 

데이터 액세스 기술 유형

  • SQL 중심 기술
    자바 코드안에서 직접 sql 쿼리문을 작성하여 DB에 접근 하는 기술을 말한다.
    mybatis, Spring JDBC 등등


  • 객체(Object) 중심 기술
    자바 코드안에 sql문이 들어가지 않고, 모든 데이터를 객체의 관점으로 보는 기술을 말한다.
    Java 객체(Object)를 이용해 애플리케이션 내부에서 이 Java 객체(Object)를 SQL 쿼리문으로 자동 변환 한 후에 데이터베이스의 테이블에 접근한다.

    이러한 객체 중심 기술을 ORM(Object-Relational Mapping)이라고 한다.
    대표적인 기술로는 Spring Data JDBC, JPA(Java Persistence API), Spring Data JPA, 가 있다

Spring Data JDBC란?

객체 중심 기술 중 하나이지만, JPA에 비해서는 기술 복잡도가 낮은 수준의 기술이다.

 

Spring Data JDBC 사용법

  1. 의존성 추가
dependencies {
	...
	...
	implementation 'org.springframework.boot:spring-boot-starter-data-jdbc'
	runtimeOnly 'com.h2database:h2'
}

implementation 'org.springframework.boot:spring-boot-starter-data-jdbc' : Spring Data JDBC 라이브러리 추가

runtimeOnly 'com.h2database:h2' : 인메모리 DB 사용을 위한 H2 라이브러리 추가

 

 

+ application.yml 과 application.properties 차이

스프링 프로젝트에 있는 resources 디렉토리에는 

application.properties 라는 파일이 존재하는데, 해당 파일은 현재 프로젝트내에 존재하는 라이브러리 (의존성) 의 속성값들을 설정할 수 있는 파일이다.

해당 파일을 application.yml로 확장자 변경을 해주면 속성들을 계층단위로 기입이 가능하다.

 

- application.yml 모습

spring:
  h2:
    console:
      enabled: true

 

 

H2 설정 적용 

spring:
  h2:
    console:
      enabled: true
      path: /h2     # (1) 콘솔 접속 URL 고정, localhost:8080/h2 로 접속 가능
  datasource:
    url: jdbc:h2:mem:test     # (2) JDBC URL 고정, jdbc:h2:mem:test으로 접속 가능

해당 설정 내용을 application.yml 에 기입하여 적용한다.

 

 

Spring Data JDBC 라이브러리 추가로 인한 DB접근 코드

import org.springframework.data.repository.CrudRepository;

public interface MessageRepository extends CrudRepository<Message, Long> {
}

DB에 접근하는 Repository인터페이스의 정의 내용이다.

중요한것은extends CrudRepository<Message, Long> 부분이다.

MessageRepository는 그냥 우리가 정의한 interface명이고,

실제 DB에 접근하여 CRUD 기능을 수행하는 녀석이

CrudRepository이며, 해당 Repository는 Message라는 엔티티를 사용하여 DB과 통신하겠다는 의미이다.

그리고 Message 와 같은 한 Entity는 DB내에서 한 Table을 의미한다.

그리고 뒤에 Long은 Message 엔티티의 ID 필드 타입, Message 테이블에서의 Primary Key의 타입을 의미한다.

 

 

즉, 다시한번 정리하면 아래의 내용처럼 중간 매개체 역할을 하는것이다.

 

현재 애플리케이션내의 Message 엔티티       <---------  MessageRepository  ---------->         DB상의 Message 테이블

 

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

추가로 인해 CrudRepository 인터페이스의 사용이 가능하다.

 

위에 내용을 보니 단순히 interface 만 정의하였는데, 구현체는 어디있나 할것이다.

구현체는 런타임시에 Spring Data JDBC가 만들어 낸다.

 

- 설명

CrudRepository is a Spring data interface and to use it we need to create our interface by extending CrudRepository for a specific type. Spring provides CrudRepository implementation class automatically at runtime. It contains methods such as save , findById , delete , count etc

참조 : https://www.concretepage.com/spring-5/spring-data-crudrepository-example

 

Spring Data CrudRepository Example

This page will walk through Spring Data CrudRepository example. It provides generic CRUD operation on a repository for a specific type.

www.concretepage.com

 

현재까지 상황

H2 라이브러리 추가로 런타임시에 DB도 동작하도록 하였고.

Spring Data JDBC 라이브러리 추가로 DB 접근 방법도 마련하였다.

그래서 CrudRepository 를 사용하여 DB 접근도 가능하다.

 

그러나, 정작 DB내에 테이블이 존재하지 않는다.

우리는 현재 H2, 즉 인메모리 DB를 사용하기 때문에 

애플리케이션 작동시 테이블이 생성되도록 하면 될것이다.

 

  • application.yml에 스키마 로케이션 속성 추가

spring:
  h2:
    console:
      enabled: true
      path: /h2     
  datasource:
    url: jdbc:h2:mem:test
  sql:
    init:
      schema-locations: classpath*:db/h2/schema.sql

  sql:
    init:
      schema-locations: classpath*:db/h2/schema.sql

부분을 추가해주면,

애플리케이션 구동시 작동되는 H2 DB에 schema.sql 에 정의되어 있는 쿼리를 작동시켜준다.

 

schema.sql 내부의 내용

CREATE TABLE IF NOT EXISTS MESSAGE (
    message_id bigint NOT NULL AUTO_INCREMENT,
    message varchar(100) NOT NULL,
    PRIMARY KEY (message_id)
);

 

 

classpath 는 src/main/resources 경로를 의미하며

schema.sql의 경로는 src/main/resources/db/h2’ 디렉토리내에 위치해 있다.

 

 

 

애플리케이션내의 Entity와 DB 테이블의 매핑 개념

  • Message Entity 정의 내용
@Getter
@Setter
public class Message { //테이블명

    @Id
    private long messageId;
    private String message;
}

 

  • Message Table 의 Create 문
CREATE TABLE IF NOT EXISTS MESSAGE (
    message_id bigint NOT NULL AUTO_INCREMENT,
    message varchar(100) NOT NULL,
    PRIMARY KEY (message_id)
);

 

즉, 위 에 Entity와 Table이 매핑이 되는것인데 매핑 되는 개념은 다음과 같다

  • @Id가 붙은 필드는 Table의 Primary Key와 매핑이 된다.

    @Id라는 애노테이션이 Primary Key와 매핑된다는것을 명시적으로 알려주기 때문에,
    테이블내의 필드명인 message_id 와 Entity내의 필드명인 messageId 가 같지 않아도 알아서 매핑이 되는것이다.
  • @Id가 아닌 필드들은 Table 내의 필드와 이름을 맞춰주어야 한다.

    Entity내의 message 필드와 Table 내의 message 필드가 이름이 같은 것을 확인 할 수 있다.
    @Id가 아닌 Entity내의 필드들은 Table내의 필드명과 일치시켜 주어야 한다.