김영한 님의 "자바 ORM 표준 JPA 프로그래밍" 책을 정리한 포스팅 입니다.
1. 영속성 컨텍스트
- 엔티티 객체의 영속화 작업을 관리하는 작업 영역
- 1차 캐시, 해당 엔티티 관련 내부 쿼리 저장소
역할
역할 | 설명 |
엔티티 상태 관리 |
엔티티를 데이터베이스와 동기화함 (EntityManager에 의해 관리됨)
|
트랜잭션 범위 |
영속성 컨텍스트는 트랜잭션 단위로 엔티티를 관리
- 트랜잭션이 시작되면 활성화되고, 종료 시 커밋 또는 롤백됨 |
캐시 기능 |
이미 로드된 엔티티는 다시 데이터베이스 조회 없이 재사용됨.
|
동작
동작 | 설명 |
자동 플러시 |
트랜잭션 커밋 전에 영속성 컨텍스트에서 변경된 데이터를 자동으로 데이터베이스에 반영.
|
수동 플러시 |
영속성 컨텍스트의 변경 사항을 강제로 데이터베이스에 반영. (entityManager.flush())
|
예제) 자동 플러시
더보기
@DataJpaTest
@TestPropertySource(locations = "classpath:application-test.yml")
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
@ContextConfiguration(classes = Main.class)
public class FlushTest {
@Autowired
private UserRepository userRepository;
@Test
@Order(1)
@Transactional
@Commit
void auto_flush_test1() {
userRepository.save(new User("auto flush"));
// entityManager.flush() 호출 안해도 자동으로 해줌
}
@Test
@Transactional
void auto_flush_test2() {
assertNotNull(userRepository.findByName("auto flush"));
// 조회 성공
}
}
장점
장점 | 설명 |
성능 최적화 |
1차 캐시와 자동 플러시 기능을 통해 불필요한 데이터베이스 접근을 최소화.
|
엔티티 관리 |
엔티티의 생명주기를 자동으로 관리하여 데이터베이스와 객체 간의 동기화를 효율적으로 처리.
|
2. 엔티티 생명주기
상태 | 설명 |
New / Transient (비영속) |
엔티티 객체가 생성된 시점의 상태.
영속성 컨텍스트와 전혀 연관이 없습니다. 데이터베이스에 반영되지 않은 상태입니다. |
Managed (영속) |
영속성 컨텍스트에 저장된 상태.
엔티티가 영속성 컨텍스트의 관리 하에 있으며, 변경 사항이 자동으로 동기화됩니다. |
Detached (준영속) |
영속성 컨텍스트에서 저장되었다가 분리된 상태.
더 이상 관리되지 않습니다. |
Removed (삭제) | 엔티티가 삭제된 상태. 데이터베이스에서 삭제될 예정 |
예제
더보기
@DataJpaTest
@TestPropertySource(locations = "classpath:application-test.yml")
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
@ContextConfiguration(classes = Main.class)
public class EntityStatusTest {
@Autowired
private UserRepository userRepository;
@PersistenceContext
private EntityManager entityManager;
@Test
@Transactional
void testEntityStatus() {
// New / Transient 상태
User newUser = new User("test");
assertTrue(!entityManager.contains(newUser));
// Managed 상태
userRepository.save(newUser);
assertTrue(entityManager.contains(newUser));
// Detached 상태
entityManager.detach(newUser);
assertTrue(!entityManager.contains(newUser));
// Removed 상태
userRepository.delete(newUser);
assertTrue(!entityManager.contains(newUser));
assertNull(userRepository.findByName("test"));
}
}
Removed 상태
- personRepository.delete(person)를 호출하면 해당 엔티티는 removed 상태에 들어감
- 실제로 데이터베이스에서 삭제됩니다
3. 상태 메서드
메서드명 | 설명 | 동작 방식 | 특징 / 주의사항 |
find() | 엔티티 조회 | 1. 1차 캐시 조회 2. 없으면 DB 조회 후 1차 캐시에 저장 |
식별자(PK)로 조회 |
persist() | 엔티티 등록 | 1. 영속성 컨텍스트 등록 2. 1차 캐시에 저장 3. 쓰기 지연 저장소에 INSERT 쿼리 저장 |
쓰기 지연 (flush 또는 커밋 시 DB 반영) |
flush() | 변경사항 반영 | 1. 스냅샷과 비교 2. 변경 감지 시 UPDATE 쿼리 생성 3. 내부 쿼리 저장소에 전송 |
UPDATE 쿼리 시 모든 필드 업데이트 - 재사용성 ⬆️ / 데이터 전송량 ⬆️ - @DynamicUpdate: 수정될 필드만 업데이트 Flush Mode - FlushModeType.AUTO: 커밋 전, JPQL 실행 전 - FlushModeType.COMMIT: 커밋 전 |
detach() | 준영속 전환 | 엔티티를 영속성 컨텍스트에서 분리 |
entityManager.contains()가 false 반환
|
merge() | 준영속 → 영속 전환 | 새 영속 인스턴스 생성 및 반환 인수는 그대로 준영속 상태 유지 |
반환 객체 사용해야 함 |
remove() | 엔티티 삭제 | 영속 상태 → 삭제 상태로 전환 삭제 쿼리는 flush/커밋 시 실행 |
준영속 상태의 엔티티에는 사용 불가
|
clear() | 컨텍스트 초기화 | 모든 영속 엔티티를 준영속으로 전환 |
flush 없이 수행 시 변경사항 손실
|
close() | 컨텍스트 종료 | EntityManager 종료 | 재사용 불가 상태가 됨 |
예제) flush() - @DynamicUpdate
더보기
@Entity
public class User { ... }
update user set name=?, nickname=? where id=?
- 기본적으로 모든 필드를 대상으로 업데이트됨
@Entity
@DynamicUpdate
public class User { ... }
update user set name=? where id=?
- @DynamicUpdate 사용 시, 수정될 필드만 업데이트 됨
예제) merge()
더보기
@Test
@Transactional
void merge() {
User detached = new User("auto flush");
User merged = entityManager.merge(detached);
assertFalse(entityManager.contains(detached));
assertTrue(entityManager.contains(merged));
}
- 새로운 영속 상태의 객체가 반환됨
- 반환된 객체로 작업해야 함
출처
'Spring > Spring Data JPA' 카테고리의 다른 글
[자바 ORM 표준 JPA 프로그래밍] 5. 연관관계 매핑 기초 (0) | 2023.12.27 |
---|---|
[자바 ORM 표준 JPA 프로그래밍] 4. 엔티티 매핑 (1) | 2023.11.28 |
[자바 ORM 표준 JPA 프로그래밍] 2. JPA 시작 (0) | 2023.11.28 |
[자바 ORM 표준 JPA 프로그래밍] 1. JPA 소개 (0) | 2023.11.28 |
[Spring Data JPA] 2-2. Transactionality (0) | 2023.10.18 |