1️⃣ persist, merge, remove, detach — 영속성 컨텍스트
| 메서드 | 설명 | 주의할 점 |
| persist(entity) | 새 엔티티를 영속 상태로 등록 | 식별자가 없다면 자동 생성됨. 이미 있는 엔티티에 쓰면 예외 발생 |
| merge(entity) | 준영속 or 비영속 엔티티의 값을 복사해서 새 영속 엔티티 생성 | 원본 객체는 여전히 준영속 상태 |
| remove(entity) | 영속 상태인 엔티티를 삭제 예약 | 트랜잭션 커밋 시 delete 쿼리 실행됨 |
| detach(entity) | 엔티티를 영속성 컨텍스트에서 분리 → 준영속 상태로 전환 | 이후 변경해도 DB 반영 X |
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
Member member = new Member("sukh"); // 비영속
em.persist(member); // 영속
em.detach(member); // 이제 준영속. 변경해도 DB 반영 안됨
em.getTransaction().commit();
2️⃣ 1차 캐시 & 동일성 보장 (== 비교 가능)

em.persist() 하면 DB에 insert 전이라도 1차 캐시에 올라감.
같은 트랜잭션 내에서 find() 하면 DB에서 가져오는 게 아니라 캐시에서 즉시 반환.
따라서 == 연산자로 비교해도 동일 객체로 간주됨.
Member member1 = em.find(Member.class, 1L);
Member member2 = em.find(Member.class, 1L);
System.out.println(member1 == member2); // true → 동일성 보장
3️⃣ 변경 감지 (Dirty Checking)
- @Transactional 안에서 조회한 영속 상태 객체를 setter 등으로 변경하면,
- 트랜잭션 커밋 시점에 flush()가 호출되어 변경 내용 감지 → update SQL 자동 생성

Member member = em.find(Member.class, 1L); // 영속
member.setName("newName"); // setter 사용
em.getTransaction().commit();
// 이 시점에 JPA가 이전 스냅샷과 비교해서 update 쿼리 날림
4️⃣ 요약
1. persist() → 비영속 → 영속
2. detach() → 영속 → 준영속
3. merge() → 복제본 생성 후 영속
4. remove() → 삭제 예약
5. 1차 캐시 덕분에 동일성 보장 (==도 OK)
6. 변경 감지는 커밋 직전 flush()에서 작동
5️⃣ 다음 공부 할 것
1. 지연 로딩과 즉시 로딩의 차이
2. Flush 타이밍 (트랜잭션 커밋, JPQL 실행 전 등)
3. 준영속 상태로 전환되는 시점과 활용법
'TIL' 카테고리의 다른 글
| [250416] 스프링 심화 과제 회고 (2) | 2025.04.16 |
|---|---|
| [250414 TIL] 뉴스피드 KPT (2) | 2025.04.14 |
| [250409] N+1, 인덱싱, 썸네일 (1) | 2025.04.09 |
| [250408 TIL] 뉴스피드 좋아요 리팩토링 및 검색기능 추가 (3) | 2025.04.08 |
| [250407 TIL] 뉴스피드 팀프로잭트 (3) | 2025.04.07 |