목차

    불편함을 코드로 지웁니다.

    개발 공부 노트, 개발 도구와 문제를 해결한 과정, AI 프롬프트와 Obsidian 활용법을 정리합니다.

      ⏳ Time Log/TIL · 하루

      [TIL] Day 67 — JPA 영속성 컨텍스트 심화 (1/22)

      this.Serena 2026. 6. 8. 21:32

      [TIL] Day 67 — JPA 영속성 컨텍스트 심화 (1/22)

      날짜: 2026-01-22
      기술 스택: Spring Boot JPA Hibernate 영속성 컨텍스트


      한 줄 요약: JPA 영속성 컨텍스트의 핵심 개념 — 1차 캐시, 변경 감지(Dirty Checking), 지연 로딩 동작 원리 정리


      JPA 영속성 컨텍스트 (Persistence Context)

      엔티티를 저장하는 논리적 공간. EntityManager가 관리하는 1차 캐시 역할

      엔티티 생명주기

      비영속 (new)
      ↓ em.persist()
      영속 (managed)    ← 1차 캐시에 저장, 변경 감지 대상
      ↓ em.detach() / em.clear() / em.close()
      준영속 (detached) ← 컨텍스트에서 분리, 변경 감지 안 됨
      
      영속 (managed)
      ↓ em.remove()
      삭제 (removed)    ← DB 삭제 예약

      1차 캐시 — 같은 트랜잭션 내 DB 조회 최소화

      // 첫 번째 find() → DB 쿼리 발생
      Member member1 = em.find(Member.class, 1L);
      
      // 두 번째 find() → 1차 캐시에서 반환, DB 쿼리 없음
      Member member2 = em.find(Member.class, 1L);
      
      System.out.println(member1 == member2); // true (동일 인스턴스)

      변경 감지 (Dirty Checking)

      em.update() 같은 메서드 없이 필드만 바꿔도 트랜잭션 커밋 시 자동으로 UPDATE 쿼리 발생

      @Transactional
      public void changePrice(Long itemId, int newPrice) {
          Item item = itemRepository.findById(itemId).orElseThrow();
          item.setPrice(newPrice); // 별도 save() 호출 없이 자동 반영
      }

      원리: 영속성 컨텍스트는 엔티티를 처음 조회할 때 스냅샷을 저장
      → 커밋 시점에 현재 상태와 스냅샷 비교 → 다르면 UPDATE 쿼리 생성

      지연 로딩 (Lazy Loading) 주의사항

      @OneToMany(mappedBy = "order", fetch = FetchType.LAZY)
      private List<OrderItem> orderItems; // 실제 접근 시 쿼리 발생

      트랜잭션 밖에서 지연 로딩된 컬렉션에 접근하면 LazyInitializationException 발생
      → 해결책: @Transactional 범위 안에서 처리하거나 fetch join 사용


      더 알아볼 것

      • @Transactional(readOnly = true) — 읽기 전용 트랜잭션에서 Dirty Checking 비활성화 효과
      • OSIV (Open Session In View) 패턴과 그 문제점
      • N+1 문제 해결 — fetch join vs @EntityGraph
      • em.flush()와 em.clear()를 명시적으로 사용하는 케이스