우리 서비스에서 매일 정각마다 수행하는 스케줄러가 있는데, 아래같은 에러가 발생했다.
20250119T000002 scheduling-1 ERROR o.s.s.s.TaskUtils$LoggingErrorHandler Unexpected error occurred in scheduled task
org.hibernate.LazyInitializationException: could not initialize proxy [com.gamzabat.algohub.feature.user.domain.User#8] - no Session
...
로그를 보면 scheduled task에서 error가 발생했음을 알 수 있다. 그 중, User 엔티티의 proxy를 initialize 할 수 없다는 내용이다.
기본적으로 지연로딩은 영속성 컨텍스트에서 객체를 접근할 수 있어야 한다는 조건이 있다. LazyInitializationException
은 지연 로딩으로 엔티티를 조회할 때, 해당 엔티티가 포함된 영속성 컨텍스트가 닫혀있거나 접근할 수 없는 상태일 경우 발생한다.
현재 우리 프로젝트에서는 OSIV 설정을 안 했으므로 스프링의 기본 영속성 컨텍스트 범위를 따른다. 즉, 영속성 컨텍스트가 유지되는 범위는 @Transactional
적용 범위가 된다.
기존에 있던 스케줄러 메소드는 @Transactional
이 없었다.
@Scheduled(cron = "0 0 0 * * ?", zone = "Asia/Seoul")
public void dailyProblemScheduler() {
...
notifyProblemStartsToday(now);
...
}
private void notifyProblemStartsToday(LocalDate now) {
List<Problem> problems = problemRepository.findAllByStartDate(now);
for (Problem problem : problems) {
notificationService.sendNotificationToMembers(
...
groupMemberRepository.findAllByStudyGroup(problem.getStudyGroup()),
...
);
}
}
...
즉, 위 코드에서problems
와 groupMemberRepository.findAllByStudyGroup()
으로 찾은 데이터들은 영속성 컨텍스트에 포함되지 않는 것이다.
이 상태로 sendNotificationToMembers()
메소드를 호출하면서, 파라미터로는 영속성 컨텍스트에 포함 안 된 members를 넘겨준다. 그래서 sendNotificationToMembers()
메소드의 로직 중, 아래 코드에서 에러가 발생한다.
if (setting.isAllNotifications() && isSettingOn(setting, category))
users.add(member.getUser().getEmail());
member.getUser().getEmail()
로 User 데이터를 지연 조회 하려는데, member 객체가 현재 영속성 컨텍스트에 포함되지 않으니 LazyInitializationException
가 발생하는 것이다.
LazyInitializationException
를 해결할 수 있는 방법으로는 OSIV를 사용해 영속성 컨텍스트 범위를 열어주거나, 지연로딩 대신 EAGER를 사용하는 방법도 있었다. 하지만 이번 케이스에서는 영속성 컨텍스트의 범위가 문제 되는 것이었다.
그래서 기존에 영속성 컨텍스트에 포함되지 않던 members가 포함될 수 있게 수정하고자 했다. 그 방법으로 스케줄러 메소드 자체에 @Trnasactional
을 붙여서 영속성 컨텍스트에 포함되도록 만들어 해결했다.
@Transactional
@Scheduled(cron = "0 0 0 * * ?", zone = "Asia/Seoul")
public void dailyProblemScheduler() {
...
}
참고
https://strong-park.tistory.com/entry/orghibernatelazyinitializationexception-could-not-initialize-proxy-%EC%97%90%EB%9F%AC-%ED%95%B4%EA%B2%B0
https://stackoverflow.com/questions/345705/hibernate-lazyinitializationexception-could-not-initialize-proxy