영속성 컨텍스트란 엔티티를 영구 저장하는 환경이다.
엔티티를 메모리에서 관리하는 일종의 캐시, JPA는 이 영속성 컨텍스트를 통해 엔티티를 관리하고 수정한다.
실제 spring boot 프로젝트 중 "채용 게시판"기능을 JPA로 구현했는데, 실제 코드를 통해 정리했다.
@Entity // 이 클래스는 JPA 엔터티. 데이터베이스 테이블과 매핑
@Getter
@Setter
public class RecruitmentPostEntity {
@Id // 기본 키
@GeneratedValue(strategy = GenerationType.IDENTITY) // 기본키 생성 전략. IDENTITY는 자동 증가
private Long id;
private String title;
@Column(columnDefinition = "TEXT") // 텍스트타입
private String content;
@Enumerated(EnumType.STRING) // enum 값을 문자열로 저장
private PostStatus status;
private LocalDate startDate;
private LocalDate endDate;
private String createdBy;
@CreatedDate // 엔터티가 생성될 때 자동으로 현재시간 저장
private LocalDateTime createdAt;
}
@Service
@RequiredArgsConstructor
@Transactional(readOnly = true)
/*
* 클래스 레벨의 readOnly=true 는 기본적으로 모든 메소드가 읽기 전용임을 설정, 쓰기가 필요한 특정 메소드에서만
* 별도로 @Transactional을 설정하여 오버라이드하는 패턴.(DB가 리소스를 더 효율적으로 사용)
*/
public class RecruitmentPostService {
private final RecruitmentPostRepository recruitmentPostRepository;
public List<RecruitmentPostEntity> getAllPosts() {
return recruitmentPostRepository.findAll();
}
@Transactional // 데이터를 변경하는 작업. (삽입)
public RecruitmentPostEntity createPost(RecruitmentPostEntity post) {
return recruitmentPostRepository.save(post);
}
@Transactional
public RecruitmentPostEntity updatePost(Integer id, RecruitmentPostEntity updatedPost) {
RecruitmentPostEntity post = getPost(id);
post.setTitle(updatedPost.getTitle());
post.setContent(updatedPost.getContent());
post.setStatus(updatedPost.getStatus());
post.setStartDate(updatedPost.getStartDate());
post.setEndDate(updatedPost.getEndDate());
return post;
}
@Transactional
public void deletePost(Integer id) {
recruitmentPostRepository.deleteById(id);
}
}
위와 같은 Entity구조와 Service로직이 있다고 가정한다면,
RecruitmentPostEntity post = getPost(id);
이 부분에서 영속성 컨텍스트에 엔티티를 로드한다.
그리고,
return post;
트랜잭션을 종료하며 자동 저장한다.
영속성 컨텍스트의 주요 특징
1. 1차 캐시
영속성 컨텍스트는 1차 캐시를 제공한다. 동일한 엔티티를 조회할 때 데이터베이스 대신 메모리에서 가져온다.
// 최초 조회: DB에서 조회
Post post1 = repository.findById(1).get();
// 두 번째 조회: 1차 캐시에서 조회 (DB 조회 없음)
Post post2 = repository.findById(1).get();
2. 변경 감지(Dirty Checking)
영속성 컨텍스트는 엔티티의 변경을 자동으로 감지하여 데이터베이스에 반영한다. 위의 updatePost() 메소드에서 별도의 save() 호출이 없는 것이 바로 이것 때문이다.
@Transactional // 트랜잭션 시작
public void updateTitle(Integer id, String newTitle) {
RecruitmentPostEntity post = getPost(id); // 영속성 컨텍스트에 로드
post.setTitle(newTitle); // 변경 감지 동작
// repository.save(post) 불필요 // 트랜잭션 종료 시 자동 저장
}
3. 지연 쓰기(Write Behind)
변경된 내용을 바로 데이터베이스에 반영하지 않고, 트랜잭션이 커밋될 때 모아서 반영한다. 이는 데이터베이스 접근을 최적화하는 역할을 한다.
'자바 > 스프링, 스프링부트' 카테고리의 다른 글
필드 주입 vs 생성자 주입 (0) | 2025.01.23 |
---|---|
@PathVariable, @RequestParam (0) | 2024.12.05 |
@RequestBody, @ResponseBody (0) | 2024.12.03 |
Controller (0) | 2024.12.02 |
스테레오타입 어노테이션(Stereotype Annotations) (0) | 2024.11.29 |