커스텀 Repository — QueryDSL 연동을 위한 확장 패턴
1. 개요 JpaRepository의 메서드 이름 쿼리와 @Query로 해결할 수 없는 경우가 있다. 동적 조건이 많거나, QueryDSL 같은 외부 라이브러리를 써야 하거나, 복잡한 집계 쿼리가 필요한 경우다. 이때 커스텀 Repository 패턴을 사용한다. 이 글에서는 커스텀 Repository의 구조, 명명 규칙, EntityManager 직접...
1. 개요 JpaRepository의 메서드 이름 쿼리와 @Query로 해결할 수 없는 경우가 있다. 동적 조건이 많거나, QueryDSL 같은 외부 라이브러리를 써야 하거나, 복잡한 집계 쿼리가 필요한 경우다. 이때 커스텀 Repository 패턴을 사용한다. 이 글에서는 커스텀 Repository의 구조, 명명 규칙, EntityManager 직접...
1. 개요 엔티티 전체를 조회하면 필요 없는 컬럼까지 DB에서 읽어온다. 목록 조회에서 제목과 가격만 필요한데 SELECT *를 날리는 셈이다. Projection은 필요한 필드만 선택적으로 조회해서 데이터 전송량과 메모리 사용을 줄이는 기법이다. Spring Data JPA는 인터페이스 기반, 클래스(DTO) 기반, 동적 Projection 세 가지...
1. 개요 목록 조회에서 전체 데이터를 한 번에 가져오면 메모리가 터진다. 페이징은 이를 조각 단위로 잘라서 가져오는 방식이다. Spring Data JPA는 Pageable, Page, Slice 등의 추상화로 페이징 처리를 단순하게 만들어준다. 이 글에서는 PageRequest 생성 방법, Page와 Slice의 차이, COUNT 쿼리 분리 최적화...
1. 개요 메서드 이름 쿼리는 단순 조건에서 강점을 보이지만, 조건이 복잡하거나 JOIN이 필요하면 한계에 부딪힌다. @Query는 JPQL 또는 SQL을 직접 작성해서 이 한계를 극복한다. 이 글에서는 @Query의 기본 사용법, 파라미터 바인딩 방식, 네이티브 쿼리, 그리고 UPDATE/DELETE 벌크 연산 처리까지 다룬다. 주제 내용 @Quer...
1. 개요 Spring Data JPA는 메서드 이름을 파싱해서 JPQL을 자동으로 생성한다. findByTitle이라고 선언하면 SELECT b FROM Book b WHERE b.title = :title 쿼리가 만들어진다. 별도 SQL 없이 메서드 선언 하나로 쿼리가 완성되는 구조다. 이 방식을 파생 쿼리(Derived Query) 또는 메서드 ...
1. 개요 Spring Data JPA를 쓰다 보면 JpaRepository를 상속하는 인터페이스 하나만 만들어도 저장, 조회, 삭제가 전부 동작한다. 왜 그런지, 내부에서 무슨 일이 벌어지는지 이해하고 있어야 나중에 커스터마이징이나 성능 튜닝을 제대로 할 수 있다. 이 글에서는 Repository 인터페이스 계층 구조, 각 계층이 제공하는 메서드, ...
1. 실습 구조 기존 Member와 Book에 LoanRecord(대출 기록)를 추가해서 연관관계 매핑 전체를 단계별로 실습한다. 1 2 3 4 5 6 7 8 9 10 Step 1. Book에 @OneToMany 양방향 추가 Step 2. Member에 @OneToMany + cascade + orphanRemoval 추가 Step 3. LoanRec...
1. 영속성 전이 (Cascade) 영속성 전이는 부모 엔티티에 특정 작업을 수행할 때 자식 엔티티에도 자동으로 같은 작업이 전파되는 기능이다. 연관관계 매핑과는 별개의 기능이고, @OneToMany / @ManyToOne 어노테이션의 cascade 속성으로 설정한다. 1 2 3 4 5 6 7 8 9 10 // cascade 없을 때 — 각각 pers...
1. @ManyToMany를 사용하면 안 되는 이유 Member와 Book은 다대다(M:N) 관계다. 한 회원이 여러 책을 빌릴 수 있고, 한 책이 여러 회원에게 빌려질 수 있다. JPA는 @ManyToMany로 이 관계를 표현할 수 있지만 실무에서는 절대 사용하지 않는다. 1 2 3 4 5 6 7 8 9 10 11 // @ManyToMany — 사용...
1. 연관관계 주인 개념 객체 세계에서 양방향 매핑은 사실 단방향 매핑 두 개다. Member가 LoanRecord를 참조하고, LoanRecord도 Member를 참조한다. 그런데 DB에서 FK는 하나다. loan_record 테이블의 member_id 컬럼 하나가 양쪽의 관계를 표현한다. 두 객체 중 어느 쪽의 참조가 변경될 때 이 FK를 갱신할지...
1. 연관관계 매핑이 필요한 이유 Phase 1에서 다뤘던 JDBC의 패러다임 불일치 중 하나가 연관관계였다. 객체는 참조로 다른 객체를 가리키지만, DB는 FK(외래 키)로 연관을 표현한다. JPA의 연관관계 매핑은 이 불일치를 해결한다. 연관관계 매핑을 이해하려면 항상 세 가지 개념을 함께 생각해야 한다. 방향: 단방향(한쪽만 참조), 양방향(서로...
1. 실습 도메인 소개 이론으로 배운 영속성 컨텍스트 개념을 실제 코드로 확인하는 실습이다. 도메인은 도서 대출 시스템으로, Book 엔티티 하나로 생명주기 · 1차 캐시 · 쓰기 지연 · 더티 체킹 전체를 단계별로 체험한다. 1 2 3 4 5 6 Step 1. Book 엔티티 작성 ← @Entity, @Column, @Enumerated 적용 Ste...
1. Auditing이란 엔티티가 생성되거나 수정된 시간, 그 주체를 자동으로 기록하는 것이 Auditing(감사)이다. 모든 테이블에 created_at, updated_at을 넣는 것은 운영 시 문제 추적을 위해 실무에서 거의 필수로 사용된다. Spring Data JPA의 Auditing 기능을 사용하면 이를 자동으로 처리할 수 있다. 2. 기본...
1. 왜 상속 매핑이 필요한가 객체지향에서는 상속이 자연스러운 개념이다. 그런데 RDB에는 상속 개념이 없다. JPA는 이 불일치를 3가지 전략으로 해결한다. 1 2 3 4 5 // 객체 모델 abstract class Item { Long id; String name; int price; } class Album extends Item { Strin...
1. 왜 임베디드 타입이 필요한가 엔티티를 설계하다 보면 특정 필드들이 논리적으로 하나의 개념을 나타내는 경우가 있다. 주소를 예로 들면 city, street, zipcode는 각각의 필드이지만 이 셋이 합쳐야 “주소”라는 개념이 된다. 이 필드들을 엔티티 안에 모두 나열하면 엔티티가 비대해지고 재사용도 어렵다. 1 2 3 4 5 6 7 8 9 10...
1. @Enumerated 자바의 enum 타입을 DB 컬럼에 매핑한다. 두 가지 방식이 있으며 반드시 STRING 방식을 사용해야 한다. 1 2 3 public enum MemberStatus { ACTIVE, INACTIVE, BANNED } ORDINAL 방식 — 절대 사용하지 말 것 1 2 3 @Enumerated(EnumType.ORDINAL...
1. @Entity @Entity는 해당 클래스가 JPA가 관리하는 엔티티임을 선언하는 어노테이션이다. 이 어노테이션이 붙어야만 JPA가 이 클래스를 인식하고 DB 테이블과 매핑한다. 📌 반드시 지켜야 할 제약 기본 생성자가 필수다. JPA는 DB에서 조회한 결과를 엔티티 객체로 변환할 때 내부적으로 리플렉션(Reflection)을 사용한다. 이 과정...
1. 1차 캐시 (First-Level Cache) 📌 내부 구조 1차 캐시는 EntityManager 내부에 있는 HashMap 구조다. key는 @Id 필드(PK)의 값이고, value는 엔티티 인스턴스와 그 스냅샷(최초 상태 복사본)의 쌍이다. 엔티티를 persist()하거나 find()로 조회하면 이 Map에 등록된다. 1 2 3 4 5 6 1...
1. 영속성 컨텍스트란 JPA를 처음 접하면 “왜 DB에 바로 저장하지 않고 영속성 컨텍스트라는 중간 단계가 있는 걸까?”라는 의문이 생긴다. 이 의문에서부터 시작하는 게 가장 이해가 빠르다. 예를 들어 한 HTTP 요청 안에서 아래와 같은 일이 벌어진다고 생각해보자. 1 2 3 4 Member member = findById(1L); // SELEC...
1. 4가지 상태 개요 엔티티는 영속성 컨텍스트와의 관계에 따라 4가지 상태 중 하나에 속한다. 상태 설명 특징 비영속 (New) new로 생성한 순수 자바 객체 JPA와 무관 영속 (Managed) 영속성 컨텍스트가 관리 중 더티 체킹, 지연 로딩 가능 준영속 (Detached) 관리에서 벗어난 상태 PK 있음, 더티 체킹 안됨 삭제 (Removed...
1. 더티 체킹 (Dirty Checking) 📌 em.update()가 없는 이유 JPA 이전에는 엔티티를 수정하면 개발자가 직접 UPDATE SQL을 작성하거나 session.update(entity) 같은 메서드를 호출해야 했다. JPA는 이 불편함을 영속성 컨텍스트의 “변경 감지(Dirty Checking)” 메커니즘으로 해결한다. 영속 상태의...
이 포스트는 Phase 2의 모든 내용(EntityManager, 엔티티 생명주기, 1차 캐시와 쓰기 지연, 더티 체킹과 OSIV)을 하나로 통합한 것이다. 영속성 컨텍스트는 JPA의 모든 동작의 기반이 되므로 Phase 1 직후 반드시 학습해야 한다. 💡 이 글의 전체 내용은 /tmp/phase2.md에서 생성되었습니다. 실제 파일은 fi...
1. 프로젝트 생성 📌 Spring Initializr 설정 (3.x) start.spring.io에서 프로젝트를 생성할 때 선택해야 할 항목은 다음과 같다. 항목 선택값 이유 Project Gradle - Kotlin Kotlin DSL 기준으로 진행. Groovy보다 타입 안전하고 IDE 자동완성이 좋음 Language Java Spring B...
1. JDBC의 한계 📌 JDBC란 JDBC(Java Database Connectivity)는 자바 표준 API로, 자바 애플리케이션이 관계형 데이터베이스에 접근할 수 있게 해주는 인터페이스 명세다. java.sql 패키지 하위에 정의된 Connection, PreparedStatement, ResultSet 등이 모두 JDBC 스펙에 해당한다. 실...
1. JDBC의 한계 📌 JDBC란 JDBC(Java Database Connectivity)는 자바 표준 API로, 자바 애플리케이션이 관계형 데이터베이스에 접근할 수 있게 해주는 인터페이스 명세다. java.sql 패키지 하위에 정의된 Connection, PreparedStatement, ResultSet 등이 모두 JDBC 스펙에 해당한다. 실...