카테고리 없음

백엔드 스터디 후기

myhousemouse 2026. 4. 19. 12:44

📌 기본 정보

  • 주차/주제: 5주차 - 데이터베이스 연동 기초

📚 학습 내용 요약

1. JPA와 Hibernate의 관계 및 주요 개념

JPA(Java Persistence API)

  • 자바 객체와 관계형 데이터베이스를 연결하기 위한 표준 인터페이스(API)
    • 주요 기능
      - 엔티티 매핑: 자바 클래스 ↔ DB 테이블
      - 엔티티 관리: 객체 상태(비영속, 영속, 분리, 삭제) 추적 및 CRUD 자동 처리
      - 트랜잭션 관리: 커밋·롤백 처리
      - 쿼리 언어(JPQL): 객체 지향적인 방식으로 데이터베이스에 쿼리를 날릴 수 있도록 해주는 JPQL(Java Persistence Query Language)
    Hibernate
    • JPA를 구현한 대표적 ORM (Object-Relational Mapping) 프레임워크
    • 추가 기능
      • 영속성 컨텍스트
        • 1차 캐시: 조회 시 메모리 캐시 우선 사용
        • 쓰기 지연(Write-Behind): 트랜잭션 커밋 전에 SQL을 모아 한 번에 실행
        • 변경 감지(Dirty Checking): 커밋 시점에 변경된 엔티티를 자동 반영
        • 지연 로딩(Lazy Loading): 실제 사용할 때만 관련 데이터를 조회
      • 자동 생성 SQL: 직접 SQL 작성 없이도 CRUD 가능

JPA는 “무엇을 할지” 규격만 정의하고, Hibernate는 “어떻게 할지” 실제 동작을 구현한 라이브러리

JPA vs Hibernate vs Spring Data JPA

JPA (Java Persistence API)
• 자바 객체와 관계형 DB를 연결하는 ORM 표준 인터페이스
• SQL 지식 없이도 엔티티 객체를 통해 DB 조작 가능
• 비즈니스 로직에 집중, DB 종속성 감소
• 복잡·무거운 쿼리는 어려움

Hibernate
• JPA 인터페이스 대표 구현체
• JDBC API 위에서 동작하는 자바용 ORM 프레임워크
• 영속성 컨텍스트
• 1차 캐시 (조회 시 캐시 활용)
• 쓰기 지연 (트랜잭션 커밋 전 배치 실행)
• 변경 감지 (커밋 시 자동 반영)
• 지연 로딩 (필요 시 쿼리 실행)

Spring Data JPA
• 스프링이 JPA 위에 편리 기능을 추가한 모듈
• PagingAndSortingRepository 상속한 JpaRepository 제공
• 인터페이스 선언만으로 기본 CRUD + 페이징·정렬 기능 자동 제공

public interface MemberRepository extends JpaRepository<Member, Long> {
} // 기본 CRUD 사용 가능

2. Entity·Repository 관련 어노테이션

어노테이션용도
@Entity 클래스가 DB 테이블과 매핑되는 JPA 엔티티임을 선언
@Id 해당 필드를 엔티티의 PK(기본 키)로 지정
@GeneratedValue PK 값을 자동 생성 전략(IDENTITY, SEQUENCE 등)으로 지정
@Table 엔티티가 매핑될 테이블 이름·스키마 등 커스터마이징
@Column 컬럼 이름·제약조건·길이 등을 커스터마이징
@Repository 해당 클래스를 JPA 데이터 액세스 계층 빈으로 등록, 예외를DataAccessException으로 변환
@Transactional 메서드 또는 클래스 단위로 트랜잭션 시작·커밋·롤백 자동 관리
@PersistenceContext EntityManager 주입 시 사용 (JPA 표준)
@Autowired Spring 컨텍스트에서 EntityManager 또는 Repository 빈 주입 시 사용

@Entity : 클래스가 DB 테이블과 매핑되는 JPA 엔티티임을 선언

@Id : 해당 필드를 엔티티의 PK(기본 키)로 지정

@GeneratedValue : PK 값을 자동 생성 전략(IDENTITY, SEQUENCE 등)으로 지정

@Entity
public class Member {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String name;
}

@Repository : 해당 클래스가 JPA 데이터 액세스 계층임을 나타내는

@Repository // @Component와 동일한 역할
public class MemberRepository {
    // 데이터베이스와의 상호작용 구현
}

@Transactional : 메서드 또는 클래스 단위로 트랜잭션 시작·커밋·롤백 자동 관리

@Transactional
public void saveMember(Member member) {
    memberRepository.save(member);
}

@Table

@Entity
@Table(name = "members")// 이 엔티티는 members 테이블에 매핑된다
public class Member {
...
// 컬럼 이름을 username 으로 지정
@Column(name = "username",
// 아무 속성 없이 쓰면, 필드명이 컬럼명이 된다
@Column                       
private String email;

@PersistenceContext

@PersistenceContext
private EntityManager em; // JPA 표준 EntityManager

@Autowired 대신 @PersistenceContext를 써야 영속성 컨텍스트가 올바르게 연결

H2 JDBC URL 모드별 차이

모드URL 예시설명
로컬 파일 모드 (Embedded File) jdbc:h2:~/test - 홈 디렉터리(~)에 test.mv.db 파일로 영구 저장- 애플리케이션 프로세스가 꺼져도 데이터 유지
TCP 서버 모드 (Server-TCP) jdbc:h2:tcp://localhost/~/test - 별도의 H2 서버 프로세스를 띄워 파일 모드 DB를 TCP로 공유- 다중 애플리케이션에서 같은 DB 접속 가능
인메모리 모드 (In-Memory) jdbc:h2:mem:testdb - 메모리 상에만 존재, 애플리케이션이 종료되면 사라짐- 빠른 테스트용, 별도 서버 불필요

http://localhost:8080/h2-console

gradle , 의존성 설정

# (1) datasource URL만으로 드라이버 자동 감지
spring.datasource.url=jdbc:h2:mem:testdb
spring.datasource.username=sa
spring.datasource.password=

# (2) Hibernate Dialect는 JPA 스타터가 자동 선택
spring.application.name=springboot-developer
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.format_sql=true
spring.jpa.defer-datasource-initialization=true

# Hibernate DDL
spring.jpa.hibernate.ddl-auto=update

# H2
spring.h2.console.enabled=true
dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-web'
    implementation 'org.springframework.boot:spring-boot-starter-jdbc'
    testImplementation 'org.springframework.boot:spring-boot-starter-test'
    testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
    implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
    runtimeOnly 'com.h2database:h2' // 인메모리 데이터베이스
    implementation 'org.projectlombok:lombok:1.18.22'  // Add Lombok dependency
    annotationProcessor 'org.projectlombok:lombok:1.18.22'  // Add annotation processor
}

SQL

CREATE TABLE member (
id   BIGINT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(50)
);
INSERT INTO member(name) VALUES('A'),('B');
SELECT * FROM member;

INSERT INTO article (title, content) VALUES ('제목 1', '내용 1');
INSERT INTO article (title, content) VALUES ('제목 2', '내용 2');
INSERT INTO article (title, content) VALUES ('제목 3', '내용 3');

 

💡 새롭게 알게 된 점 & 어려웠던 부분

  • 관련 어노테이션을 찾아보면서, 몰랐던 기능과 잘못알고 있던 지식들을 바로 잡을 수 있게 되었다.

👥 스터디 피드백

Spring Data JPA를 사용하며 느꼈던 장단점
장점

  • @Query 어노테이션사용 → JPQL 간단히 추가 가능
  • JPARepository 상속으로 기본 CRUD 모두 제공 가능
  • 트랜잭션, 예외처리가 자동 → 깔끔한 코드

단점

  • 복잡한 JOIN쿼리 같은경우 코드가 지저분해 보일 수 있음
  • 연관관계가 복잡할수록 N+1 문제가 쉽게 발생

엔티티 클래스에 비즈니스 로직을 추가하면 어떨까요?
관련 로직이 엔티티 안에 모여 있어 이해,유지보수가 용이하지만,

엔티티 내부 로직이 데이터 접근, 의존하게 되면 단위테스트가 어려울 수 있음

→ 단순 검증, 상태 전환 같은 핵심 비즈니스 로직은 엔티티 메서드로 구현해도 되지만

복잡하거나 외부 호출을 포함하는 비즈니스 로직은 서비스 계층에 두어 책임을 명확히 분리해야하지 않을까 싶음.

이 외에도 다른 팀원분들과의 토론을 진행했습니다.