Skip to content

fix : 영속성 컨텍스트 clear 문제 해결#42

Merged
oroi2009 merged 1 commit into
mainfrom
fix/#11
May 11, 2026
Merged

fix : 영속성 컨텍스트 clear 문제 해결#42
oroi2009 merged 1 commit into
mainfrom
fix/#11

Conversation

@oroi2009

Copy link
Copy Markdown
Contributor

🔍 관련 이슈


✅ 작업 분류

  • 버그 수정
  • 신규 기능
  • 프로젝트 구조 변경
  • 코드 리팩토링
  • 기능 수정

✨ 작업 내용

  1. 재투표 API 호출 시 발생하던 LazyInitializationException을 수정했습니다.
  2. CandidateVoteRepository.deleteAllByPromiseId()의 clearAutomatically = true 옵션을 제거했습니다.
  3. 벌크 delete 이후에도 같은 트랜잭션 내에서 Promise, Candidate 엔티티 상태 변경이 정상적으로 커밋되도록 유지했습니다.

👥 전달사항

문제 원인

재투표 로직에서는 기존 투표를 삭제한 뒤 약속 상태를 재투표 상태로 변경합니다.

  candidateVoteRepository.deleteAllByPromiseId(promiseId);
  promiseMember.getPromise().startRevote(LocalDateTime.now().plusHours(12));

그런데 deleteAllByPromiseId()에 아래 옵션이 설정되어 있었습니다.

  @Modifying(clearAutomatically = true, flushAutomatically = true)

clearAutomatically = true는 벌크 delete 실행 후 JPA 영속성 컨텍스트를 비웁니다. 이 때문에 같은 트랜잭션 안에서 이미 조회해둔 promiseMember가 detached 상태가 되었고,
promiseMember.getPromise()의 지연 로딩 프록시를 초기화할 수 없어 아래 예외가 발생했습니다.

Could not initialize proxy [Promise] - no session


✅ 체크리스트

  • 코드가 컴파일 및 빌드됨
  • 모든 테스트가 통과함
  • 관련 문서가 업데이트됨
  • 커밋 메시지를 확인함

💡 배운 것 / 시도한 것 / 고민한 점

  • JPA 벌크 연산은 영속성 컨텍스트를 우회해서 DB에 직접 쿼리를 실행합니다.
  • clearAutomatically = true는 벌크 연산 이후 영속성 컨텍스트를 자동으로 비우기 때문에, 같은 트랜잭션에서 Lazy proxy나 기존 조회 엔티티를 계속 사용하는 경우 문제가 될 수 있습니다.
  • 이번 경우에는 벌크 delete 이후에도 Promise.startRevote()를 호출해야 하므로, 영속성 컨텍스트를 유지하는 방식이 더 적절했습니다.
  • flushAutomatically = true는 유지해서 벌크 delete 전에 필요한 변경 사항은 먼저 DB에 반영되도록 했습니다.

@oroi2009 oroi2009 self-assigned this May 11, 2026
@oroi2009 oroi2009 added the bug Something isn't working label May 11, 2026
@oroi2009 oroi2009 merged commit 075eefa into main May 11, 2026
2 checks passed

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request modifies the CandidateVoteRepository by removing the clearAutomatically = true attribute from the @Modifying annotation on the deleteAllByPromiseId method. While this change prevents LazyInitializationException by maintaining the persistence context, it introduces a risk of data inconsistency where the application state may not reflect the database deletions. The feedback suggests verifying that subsequent transaction logic does not rely on stale entities and recommends explicit re-fetching if data integrity is critical.

boolean existsByUserIdAndPromiseId(Long userId, Long promiseId);

@Modifying(clearAutomatically = true, flushAutomatically = true)
@Modifying(flushAutomatically = true)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

clearAutomatically = true 옵션을 제거하면 벌크 삭제 연산 후에도 영속성 컨텍스트가 유지되어 LazyInitializationException을 방지할 수 있지만, 영속성 컨텍스트와 데이터베이스 간의 데이터 불일치(Stale State) 문제가 발생할 수 있는 점에 유의해야 합니다. 특히 Promise 엔티티가 CandidateVote 엔티티들과 @OneToMany 관계를 맺고 있고 해당 컬렉션이 이미 영속성 컨텍스트에 로드되어 있다면, DB에서 삭제된 데이터가 메모리상의 컬렉션에는 여전히 남아있게 됩니다. 이 트랜잭션의 남은 로직에서 해당 컬렉션을 참조하거나 삭제된 엔티티를 다시 조회하지 않는지 확인이 필요하며, 만약 데이터 정합성이 중요하다면 연산 후 필요한 엔티티를 명시적으로 다시 조회하는 방안을 고려해 보시기 바랍니다.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant