카테고리 없음
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 핸들러 역할을 분리하면 유지보수성이 좋아진다