Java & Spring 44

영속성 컨텍스트 메커니즘 - 1차 캐시 · Dirty Checking · 쓰기 지연

1. JPA와 HibernateJPA(Jakarta Persistence API) 는 자바 객체를 관계형 DB에 매핑하는 명세이다. 인터페이스와 어노테이션의 집합일 뿐, 실제 동작 코드는 없다.Hibernate 는 이 명세의 구현체다. JPA보다 먼저 존재했고, 오히려 JPA 명세가 Hibernate의 영향을 받아 만들어졌다. 구분 JPA Hibernate위치명세구현체패키지jakarta.persistence.*org.hibernate.*역할인터페이스/어노테이션 정의실제 동작 코드sprin..

Java & Spring/JPA 2026.05.09

Spring Batch 개념, 사용

배치(Batch)란?배치는 대량의 데이터를 한 번에 일괄 처리하는 방식을 말한다.실시간으로 요청이 들어올 때마다 처리하는 게 아니라, 데이터를 모아뒀다가 한꺼번에 처리하는 것이다.대표적인 사용 사례는 아래와 같다.일매출 집계 — 하루치 거래 데이터를 새벽에 한 번에 집계구독 메일 발송 — 정해진 시간에 구독자 전체에게 메일 일괄 전송데이터 백업 — 트래픽이 적은 새벽 시간대에 DB 백업Batch vs Scheduler여기서 헷갈릴 수 있는 게 Batch와 Scheduler의 차이다.구분 역할Batch대량 데이터를 일괄 처리하는 것Scheduler정해진 시간에 작업을 실행시키는 것배치는 "대량 처리"를 의미하는 것이지, 주기적으로 실행된다는 뜻이 아니다.Spring Batch는 Quartz 같은 스케줄러와..

페이지네이션의 원리? 필요성?

들어가며Spring으로 목록 API를 만들다 보면 Pageable, Page, Slice를 자연스럽게 쓰게 된다. 근데 막상 "이게 내부적으로 어떻게 동작해?"라고 물어보면 설명을 잘 못했었다. 이 글에서는 페이징이 왜 필요한지부터 OFFSET 방식의 한계, 커서 기반 페이징의 원리까지 차근차근 정리해보자!왜 페이징이 필요할까?SELECT * FROM users;데이터가 100만 건이면 이 쿼리 한 방에 전부 가져온다. 메모리가 터지고 응답도 한없이 느려진다. 잘라서 가져오는 것이 페이징이다.OFFSET 기반 페이징원리DB에서 페이징을 구현하는 가장 기본적인 방법은 LIMIT과 OFFSET을 쓰는 것이다.SELECT * FROM users ORDER BY id LIMIT 10 OFFSET 0; -- ..

[MapStruct] 내부 구현 방식 - 설계 문제 해결

문제 상황BaseEntity에서 @Setter를 제거했더니 MapStruct Mapper에서 컴파일 오류가 발생했다.error: Property "id" has no write accessor in User for target name "user.id". ReadStatus toEntity(ReadStatusCreateRequest request);error: Property "id" has no write accessor in Channel for target name "channel.id". ReadStatus toEntity(ReadStatusCreateRequest request);처음엔 단순히 Setter가 없어서 생긴 오류라고 생각했다.ignore = true를 붙이거나 Setter..

JPA Dirty Checking과 명시적 save는 무슨 차이일까?

1. Dirty Checking이란영속성 컨텍스트는 엔티티를 처음 조회하거나 persist할 때 해당 시점의 스냅샷을 내부에 보관합니다. 트랜잭션 커밋 시점에 flush가 호출되면서 현재 엔티티 상태와 스냅샷을 필드 단위로 비교해, 변경이 있으면 자동으로 UPDATE SQL을 생성합니다. 이것이 Dirty Checking입니다.트랜잭션 커밋 ↓entity manager의 flush 자동 호출 ↓dirty checking (현재 상태 vs 스냅샷 비교) ↓변경 감지 → UPDATE SQL 생성 → DB 전송 ↓JDBC commit (영구 반영)따라서 같은 트랜잭션 내에서 엔티티를 조회하고 수정하면, save() 호출 없이도 트랜잭션 커밋 시 UPDATE가 자동으로 발생합니다.@Tran..

Java & Spring/JPA 2026.04.09

Spring Data JPA는 내부적으로 어떻게 동작할까?

1. JPA vs Spring Data JPA둘을 혼용해서 쓰는 경우가 많지만 역할이 다릅니다.**JPA (Java Persistence API)**는 자바 ORM 표준 명세입니다. 인터페이스만 정의하고, 실제 구현체는 Hibernate가 담당합니다.Spring Data JPA는 JPA 위에 얹힌 추상화 레이어입니다. JpaRepository를 상속하는 것만으로 findById(), save(), delete() 같은 기본 CRUD를 자동으로 제공합니다.Spring Data JPA ↓ JPA (인터페이스) ↓ Hibernate (구현체) ↓ JDBC ↓ DB즉, 우리가 userRepository.save(user)를 호출하면 내부적으로 Hibernat..

Java & Spring/JPA 2026.04.09

Spring 프록시 원리

Spring의 프록시(Proxy)가 뭔지 제대로 이해해보자스프링을 공부하다 보면 "프록시"라는 말이 자꾸 나온다!@Transactional도 프록시, @Cacheable도 프록시, @Configuration도 프록시...도대체 프록시가 뭔지, 왜 쓰는 건지 알아보자!프록시가 뭘까?프록시를 한 마디로 표현하면 "진짜 객체 앞에 서서 호출을 가로채는 대리인" 이다.일상적인 비유로 설명하면 이렇다.팬 → 매니저(프록시) → 연예인(진짜 객체)팬이 연예인한테 직접 연락하는 게 아니라 매니저를 통해서 연락한다.매니저는 중간에서 "이 스케줄은 안 돼", "이건 전달할게" 같은 처리를 할 수 있다.코드로 보면 이렇다.// 프록시 없이 직접 호출UserService service = new UserService();s..

MapStruct

📌 1. MapStruct란?MapStruct는 객체 간 매핑 코드를 자동으로 생성해주는 라이브러리이다.주로 다음과 같은 상황에서 사용된다.DTO ↔ Entity 변환API 요청/응답 객체 변환계층 간 데이터 전달👉 핵심:반복적인 매핑 코드를 자동화하여 생산성과 안정성을 높인다.❗ 2. 기존 방식의 문제점✔️ 수동 매핑UserDto dto = new UserDto();dto.setName(user.getName());dto.setAge(user.getAge());❌ 문제점코드 반복 많음실수 발생 가능유지보수 어려움✔️ ModelMapper (대안)리플렉션 기반 자동 매핑❌ 문제점성능 저하런타임 에러 발생 가능디버깅 어려움✅ 3. MapStruct의 핵심 특징✔️ 1. 컴파일 시 코드 생성실행 전에 매..

제네릭 (Generic)

1. 제네릭이란?클래스나 메서드에서 사용할 타입을 외부에서 지정할 수 있도록 하는 문법이다.List list = new ArrayList();타입 안정성 보장명시적 캐스팅 제거컴파일 타임 오류 검출IDE 타입 추론 가능2. Generic Class기본 구조class Box { private T value; public void set(T value) { this.value = value; } public T get() { return value; }}// 사용Box box = new Box();box.set("hello");String s = box.get(); // 캐스팅 불필요 타입 매개변수 TT는 실제 타입이 아님컴파일 시 전달된 타입으로 치환됨 ..

람다 표현식 2

1. 익명 클래스 vs 람다람다는 익명 클래스의 대체 문법이지만 이 둘은 완전히 같지 않다! 익명 클래스new Runnable() { @Override public void run() { System.out.println(this); }};새로운 클래스 생성this -> 익명 객체 자신람다 Runnable r = () -> { System.out.println(this);};클래스 생성 Xthis -> 외부 객체차이 구분 익명 클래스 람다생성 구조클래스 생성클래스 없음this자기 자신외부 객체바이트코드클래스 파일invokedynamic목적객체 생성동작 전달 2. 타입 추론람다식에 타입이 존재하지 않는다. 하지만 컴파일은 정상적으로 되는데 이는 함수형 인터페이스가 이미 ..