카테고리 없음

TIL: Hibernate LazyInitializationException과 @Transactional 적용

creator7087 2025. 6. 17. 17:30

문제 상황

Spring AMQP 리스너 내에서 VolunteerTeam 엔티티를 조회 후, participants 컬렉션을 접근할 때
org.hibernate.LazyInitializationException: could not initialize proxy - no Session 예외 발생.

원인

Hibernate는 기본적으로 연관 컬렉션을 지연 로딩(Lazy Loading)한다.
이를 초기화하려면 활성화된 Hibernate 세션(트랜잭션 범위 내)이 필요하다.
리스너 등에서 트랜잭션 없이 엔티티를 조회 후 지연로딩된 필드를 접근하면 예외 발생.

해결 방법

  • volunteerTeamRepository.findWithPostAndDetailsById() 쿼리에서 필요한 연관 엔티티를 JOIN FETCH로 미리 가져오기 (부분 해결)
  • 그러나 sendToTeam() 메서드가 트랜잭션 범위 밖에서 호출되면 LazyInitializationException 발생 가능성 있음
  • 따라서 sendToTeam() 호출 시점에 트랜잭션이 활성화되어야 함 → 보통 서비스 계층 메서드에 @Transactional 붙여 트랜잭션 범위 관리 권장

적용 사례

 
@Service @RequiredArgsConstructor public class TrackingService { private final TrackingSocketHandler trackingSocketHandler; @Transactional(readOnly = true) public void sendTeamMessage(Long teamId, String event, Object payload) { trackingSocketHandler.sendToTeam(teamId, event, payload); } }
  • 서비스 계층에서 트랜잭션 범위를 관리하여, sendToTeam() 내에서 지연로딩 문제 방지
  • 핸들러에는 순수 WebSocket 세션 관리 로직만 둠으로서 역할 분리 유지

느낀 점

  • Hibernate 지연 로딩은 편리하지만 세션 관리에 유의해야 함
  • 트랜잭셔널 범위를 명확히 지정하는 게 중요하다
  • 비즈니스 로직과 WebSocket 핸들러 역할을 분리하면 유지보수성이 좋아진다