반응형
Notice
Recent Posts
Recent Comments
Link
«   2025/07   »
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
Tags
more
Archives
Today
Total
관리 메뉴

배움과 기록의 장

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

backend/spring

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

chaeunii 2025. 4. 11. 03:32

2023.2.13 작성

 

🔸 JDBC란?

- Java 기반 애플리케이션의 코드레벨에서 데이터베이스에 있는 데이터를 사용할 수 있게 데이터베이스에 접근할 수 있도록 Java에서 제공하는 표준 사양

Java 초창기(JDK 1.1) 버전부터 제공

- 자바개발자는 JDBC API를 사용해서 다양한 벤더(Oracle, MS SQL, MySQL 등)의 데이터베이스와 연동가능

( 데이터 액세스 기술의 기본이 되는 저수준(low level) API이기 때문에, JDBC의 구체적인 API 사용법을 알 필요는 없다. 하지만 Sping Data JDBC나 Spring Data JPA 같은 기술에서도 내부적으로는 JDBC를 사용하기 때문에, JDBC 동작 흐름 정도는 알아두면 Spring에서 지원하는 데이터 엑세스 기술을 사용하는 데에 도움이 된다. )

 

🔸 JDBC 동작 흐름

 

- Java 애플리케이션에서 JDBC API를 이용해 적절한 데이터베이스 드라이버를 로딩한 후, 데이터베이스와 인터렉션한다

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

 

🔸 JDBC API 사용흐름

1) JDBC 드라이버 로딩: 사용하고자 하는 JDBC 드라이버를 DriverManager라는 클래스를 통해 로딩

2) Connection 객체 생성: JDBC 드라이버가 정상로딩되면, DriverManager를 통해 데이터베이스와 연결되는 세션인 Connection 객체를 생성

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

4) Query 실행: 생성된 Statement 객체를 이용해 입력한 SQL 쿼리 실행

5) ResultSet 객체로부터 데이터 조회: 실행된 SQL쿼리문에 대한 결과 데이터 셋

6) ResultSet, Statement, Connection 객체 Close: JDBC API를 통해 사용된 객체들을 사용 이후 역순으로 close

 

🔸 Connection Pool이란?

데이터베이스 Connection을 미리 만들어서 보관하고 애플리케이션이 필요할 때 이 Connection을 제공해주는 역할을 하는 Connection 관리자

- 데이터베이스 연결을 위한 Connection 객체를 생성하는 작업은 비용이 많이 들기 때문에, 애플리케이션 로딩 시점에 객체를 미리 생성해둔 후, 필요 시에 만들어둔 Connection 객체를 사용함으로써 애플리케이션 성능을 향상시킨다

- Spring Boot 2.0 부터는  HikariCP를 기본 DBCP(Database Connection Pool)로 채택 (이전에는 Apache 재단의 오픈 소스인 Apache Commons DBCP)

 

 

🔸 Spring에서 사용할 수 있는 대표적인 데이터 액세스 기술 유형

: mybatis, Spring JDBC, Spring Data JDBC, JPA, Spring Data JPA 등

 

1) SQL 중심 기술

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

mybatis(SQL Mapper 설정 파일에 작성), Spring JDBC(JdbcTemplate 템플릿 클래스에 작성)

 

2) 객체 중심 기술 (ORM(Object-Relational Mapping))

데이터를 SQL 쿼리문 위주로 생각하는 것이 아니라 모든 데이터를 객체 관점으로 바라보는 기술

데이터베이스에 접근하기 위해 SQL 쿼리문을 직접적으로 작성하기 보다, Java 객체를 이용해 내부적으로 SQL 쿼리문으로 자동 변환 한 후 접근

- Java의 대표적인 ORM 기술: JPA(Java Persistence API)

 

🔸 Spring Data JDBC 란?

JPA처럼 ORM 기술을 사용하지만 JPA의 기술적 복잡도를 낮춘 기술이기 때문에 JPA보다 덜 어려움

- Spring Data JDBC vs JPA vs Spring Data JPA 다 배워야함

  •   Spring Data JDBC : 릴리즈 된 지도 얼마 되지 않았고, JPA보다 상대적으로 적게 사용되지만, 복잡하지 않은 애플리케이션의 경우 뛰어난 생산성을 보여줄 것이며, ORM 개념과 스프링에서의 데이터 접근 방식 등을 접하면서 이후 공부할 JPA와 Spring Data JPA를 이해하는 데에 도움 될 것
  •   JPA : 실무에서 가장 많이 사용하고 있는 기술
  •   Sping Data JPA : Spring에서 JPA 기술을 편리하게 사용하기 위한 기술 (JPA 선행)

 

🔸 Hello World 샘플코드 (Spring Data JDBC 사용하여 데이터 베이스에 "Hello World" 넣어보기!) 

 

1) 사전 준비

- 의존라이브러리 추가

dependencies {
	...
	...
     // Spring Data JDBC 사용
	implementation 'org.springframework.boot:spring-boot-starter-data-jdbc'
    // 인메모리(In-memory) DB인 H2 사용 -> 로컬 테스트 환경에서 인메모리 DB 사용 권장
	runtimeOnly 'com.h2database:h2'
}

 

- application.yml 파일에서 h2 browser 활성화 (웹브라우저 상 h2콘솔에서 데이터베이스 접속후 관리 가능)

spring:
  h2:
    console:
      enabled: true
  • application.yml 파일? Spring에서는 application.properties 또는 application.yml 파일을 통해 spring에서 사용하는 다양한 설정 정보들을 입력할 수 있다. .yml파일은 설정정보(프로퍼티)를 depth별로 입력할 수 있어 중복되는 프로퍼티의 입력을 줄여주기 때문에 .properties파일보다 더 선호되는 추세이다.

 

- h2 DB 정상적으로 동작하는지 확인

서버 실행 후 나오는 로그

  • h2 콘솔은 localhost:8080/h2-console 에서 사용가능하며, JDBC URL은 jdbc:h2:mem:722d691f-d101-4beb-bcc7-698e9a6466b2 이다.

 

브라우저로 접속한 h2 콘솔

  • 브라우저로 localhost:8080/h2-console에 접속하여 볼 수 있는 h2 콘솔이다. JDBC URL에 서버 실행 후 나오는 로그에 적혀있던 URL를 적고 connect하면 데이터베이스에 접근 가능하다

!! 그런데 JDBC URL은 애플리케이션을 실행할 때마다 랜덤하게 바뀐다 !! 그럼 connect 하기 위해 매번 바꿔줘야 하기 때문에 매우 불편하다. 이러한 문제는 application.yml 파일에  h2에 대한 추가설정을 해주면 해결할 수 있다.

 

- application.yml 파일에서  h2 DB 설정 추가(JDBC URL 일정하게 만들어주기)

spring:
  h2:
    console:
      enabled: true
      path: /h2    // 기존의 '/h2-console' 도 심플하게 바꿔줌
  datasource:
    url: jdbc:h2:mem:test  // 얘 추가!

 

 

변경 후 접속한 h2 콘솔

 

2) Hello World 샘플코드 구현

 

샘플 hello_world 패키지

 

- 이번 실습에서는, 서비스 계층의  MessageService클래스와 데이터액세스 계층의 MessageRepository 인터페이스를 어덯게 연동해서 데이터베이스에 데이터를 저장하는지가 핵심이다. 따라서 MessageServiceMessageMessageRepository 의 코드를 자세히 들여다보고, 나머지는 앞에 실습했던 내용과 동일하기 때문에 생락한다.

 

- MemberRepository 인터페이스

import org.springframework.data.repository.CrudRepository;

public interface MessageRepository extends CrudRepository<Message, Long> {
}
  • CurdRepository를 상속받고 있고, 제너릭 타입은 <Message,Long>으로 선언 되었다.
  • CurdRepository는 데이터베이스에 CURD 작업을 진행하기 위해 스프링에서 지원해주는 인터페이스다. (얘를 통해 데이터 생성, 조회, 수정 작업을 할 수 있다.)
  • 제너릭 타입을 Message로 지정해준 것은 데이터베이스에 Message를 다룬다는 것이고, Long은 Message의 식별자 를 나타내는 @Id 애터네이션이 붙어있는 Message 엔티티 멤버변수의 데이터 타입을 의미한다.

 

- MemberService 클래스

  • 방금 만든 MemberRepository는 MemberService에 DI를 통해 주입되어 사용된다.
  • MemberRepository에 별도의 코드를 작성하지 않아도, save(), findById()와 같이 CrudRepository에 정의되어 있는 메서드들을 사용하여 데이터의 생성, 조회, 수정, 삭제 작업을 할 수 있다. 
  • 아래코드는 MeberService에서 MemberRepository를 사용하는 예시코드이다.
messageRepository.save(message);

 

- Message 엔티티 클래스

import lombok.Getter;
import lombok.Setter;
import org.springframework.data.annotation.Id;

@Getter
@Setter
public class Message {  
    @Id    
    private long messageId;
    private String message;
}
  • Message라는 클래스 명은 데이터베이스의 테이블 명에 해당한다.
  • @Id 애너테이션이 붙은 멤버 변수는 엔티티의 고유 식별자 역할을 하고, 이 식별자는 데이터 베이스의 Primary key 칼럼에 해당한다.

- 여기까지 구현하고 실행 후 클라이언트쪽에서 요청을 보내면?

Table "MESSAGE" not found, 즉 Message 테이블을 발견할 수 없다는 에러가 뜬다. h2 데이터 베이스에 데이터를 저장할 Message 테이블을 만들어주지 않기 때문에 발생한 에러이므로 생성해주도록 하자.

 

 

3) h2 DB 에 Message 테이블 생성

- application.yml 파일에 DB 초기화 설정 추가

spring:
  h2:
    console:
      enabled: true
      path: /h2     
  datasource:
    url: jdbc:h2:mem:test
  sql:
    init:
      schema-locations: classpath*:db/h2/schema.sql  // 얘 추가
  • 테이블 생성을 위한 SQL 문이 추가된 schema.sql로 경로를 설정해주면, 파일에 있는 스크립트를 읽어서 애플리케이션 실행 시 데이터베이스에 테이블을 자동으로 생성해준다. 

- schema.sql에 적어준 테이블 생성을 위한 SQL문

CREATE TABLE IF NOT EXISTS MESSAGE (
    message_id bigint NOT NULL AUTO_INCREMENT,
    message varchar(100) NOT NULL,
    PRIMARY KEY (message_id)
);
  • Message 테이블은 Message 클래스 명과 매핑
  • message_id는 Message클래스의 messageId 멤버변수와 매핑
  • message는 Message 클래스의 message 멤버 변수와 매핑
  • ORM에서는 객체의 멤버 변수와 데이터베이스 테이블의 컬럼이 대부분 1대1로 매핑된다.

 

4) 실행결과 확인

Postman으로 요청 전송 후, 받은 응답

messageId를 포함하여 전송하지 않았지만, Message테이블의 message_id 칼럼에 AUTO_INCREMENT 설정이 되어있기 때문에 데이터가 저장될 때마다 자동으로 생성,증가되어 포함된다.

h2콘솔을 통해 저장된 데이터 확인

Postman에서 요청으로 전송한 메세지 "Hello, World"가 정상적으로 데이터베이스에 저장이 되었다.

 

5) (추가) 추가적인 application.yml 프로퍼티 설정

spring:
  h2:
    console:
      enabled: true
      path: /h2     
  datasource:
    url: jdbc:h2:mem:test
  sql:
    init:
      schema-locations: classpath*:db/h2/schema.sql
      data-locations: classpath*:db/h2/data.sql   //테스트 데이터 생성(INSERT문 사용)
logging:
  level:
    org:
      springframework:
        jdbc:
          core: TRACE // 데이터 저장 등 로깅

 

 

반응형

'backend > spring' 카테고리의 다른 글

[Spring] 객체지향을 위한 스프링의 노력 - IoC / DI / 컨테이너  (1) 2025.04.27
[Spring] HTTP Header, Rest Client  (0) 2025.04.11
[Spring] MVC - API 계층  (0) 2025.04.10
[Spring] MVC  (0) 2025.04.10