JAVA

[3단계] 데이터베이스 연동과 JPA (DIP)

승운노트 2025. 11. 14. 16:54

설정 - 프로파일 로컬

 

spring:
  # ===================================================================
  # 1. 데이터소스(DB) 설정
  # H2 데이터베이스에 어떻게 연결할지 스프링에게 알려줍니다.
  # ===================================================================
  datasource:
    # url: jdbc:h2:mem:solidtask -> 'solidtask'라는 이름의 메모리 기반 DB를 사용합니다.
    # 서버를 재시작하면 데이터는 사라집니다.
    url: jdbc:h2:mem:demsolidtask
    username: sa # H2 DB 기본 사용자 이름
    password: # 비밀번호는 없음
    driver-class-name: org.h2.Driver # H2 드라이버 지정

  # ===================================================================
  # 2. H2 데이터베이스 콘솔 설정
  # 개발 중 DB 테이블과 데이터를 눈으로 직접 볼 수 있게 해주는 웹 콘솔 기능입니다.
  # ===================================================================
  h2:
    console:
      enabled: true # H2 콘솔 기능 활성화
      path: /h2-console # 브라우저에서 접속할 경로 (<http://localhost:8080/h2-console>)

  # ===================================================================
  # 3. JPA 및 Hibernate 설정
  # JPA가 데이터베이스와 어떻게 상호작용할지 상세 규칙을 정합니다.
  # ===================================================================
  jpa:
    # JPA의 구현체인 Hibernate에 대한 설정
    hibernate:
      # ddl-auto: 애플리케이션 실행 시점에 DB 스키마(테이블 등)를 어떻게 처리할지 결정
      # create-drop: 실행 시점에 엔티티 기준으로 테이블을 생성하고, 종료 시점에 모두 삭제합니다. (개발용으로 편리함)
      ddl-auto: create-drop

    # JPA가 생성하고 실행하는 SQL 쿼리를 개발자가 볼 수 있도록 하는 설정
    properties:
      hibernate:
        format_sql: true # SQL 쿼리를 보기 좋게 줄바꿈하여 포맷팅
    show-sql: true # 실행되는 SQL 쿼리를 콘솔에 출력

 

 

도메인 객체를 테이블로(엔티티) 변경

package com.puzzlix.solid_task.domain.user;

import jakarta.persistence.*;
import lombok.*;

@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@Entity
@Table(name = "user_table")
@ToString
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String name;
    private String email;
    private String password;
}

 

 

package com.puzzlix.solid_task.domain.project;

import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@Entity
public class Project {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String name;
    private String description;
}

 

 

추후 연관관계 설정

 

package com.puzzlix.solid_task.domain.issue;

import jakarta.persistence.*;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@Entity
public class Issue {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String tittle;
    private String description;
    @Enumerated(EnumType.STRING)
    private IssueStatus issueStatus;

    // 추후 연관관계 필드
    private Long projectId;
    // 누가 요청(보고)
    private Long reporterId;
    // 담당자(누군가에게 할당 되어 처리 됩니다)
    private Long assigneeId;
}

 

 

package com.puzzlix.solid_task.domain.issue;

import jakarta.persistence.*;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@Entity
public class Issue {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String tittle;
    private String description;
    @Enumerated(EnumType.STRING)
    private IssueStatus issueStatus;

    // 추후 연관관계 필드
    private Long projectId;
    // 누가 요청(보고)
    private Long reporterId;
    // 담당자(누군가에게 할당 되어 처리 됩니다)
    private Long assigneeId;
}

 

우리가 직접 구축한 메모리 DB에서 JPARepository 로 변경해 보자.

 

package com.puzzlix.solid_task.domain.issue;

import org.springframework.data.jpa.repository.JpaRepository;

/**
 * 저장소 역할(규칙)을 정의하는 인터페이스
 */
// @Repository -> JpaRepository 내부에 선언 되어 있음
public interface IssueRepository extends JpaRepository<Issue, Long> {
    // JapRepository를 상속 받으면 기본적인 많은 기능을 바로 제공해준다.
}

 

중요: 이제 MemoryIssueRepository.java 파일은 더 이상 필요 없으므로, 파일 자체를 삭제하거나
@Repository 어노테이션을 제거(주석 처리)하여 스프링이 인식하지 못하도록 해야 합니다.

 

JPA 주요 장점들 조회가 두번 일어나면 캐싱이 된다 쓰기지연으로 한번에 insert 처리 할 수 있다.

 

 

 

이것이 바로 DIP(의존관계 역전 원칙)의 힘입니다. IssueService는

Memory...나 Jpa... 같은 구체적인 구현 기술(세부 사항)에 의존하지 않고,
오직 IssueRepository라는 역할(추상화)에만 의존합니다.
따라서 그 역할의 구현체가 메모리에서 JPA로 바뀌어도, IssueService는 그 사실조차 알 필요 없이 동일하게 동작합니다.