매일 자정에 실행되는 팀 랭킹 업데이트 기능을 구현하고 있다.
@Scheduled 어노테이션을 추가한 private 메서드에 @Transactional 어노테이션을 추가하니 다음과 같은 경고를 볼 수 있었다.
Methods annotated with '@Transactional' must be overridable
왜일까?
Spring Framework에서
@Scheduled와@Transactional을 함께 사용하는 경우. Spring이 두 어노테이션을 프록시 기반으로 관리하기 때문에
@Scheduled 메서드는 프록시 객체에 의해 호출되지 않기 때문에 @Transactional이 올바르게 작동하지 않는다.
@Transactional을 처리함@Scheduled는 프록시 외부에서 호출된다@Transactional이 적용되지 않을 수 있다@Transactional을 사용하기 위해서는 메서드가 프록시 객체를 통해 호출되어야 하고, 메서드가 public이어야 한다.
private 메서드는 프록시 객체에서 호출할 수 없기에 위와 같은 에러가 발생하는 것이다.
@Scheduled(cron = "0 0 0 * * *")
@Transactional
private void updateLeagueRankings() { }
// 변경
@Scheduled(cron = "0 0 0 * * *")
@Transactional
public void updateLeagueRankings() { }
@Scheduled와 @Transactional 분리@Scheduled 메서드에서 트랜젝션이 필요한 작업을 다른 서비스나 메서드로 위임한다.
@Component
public class LeagueRankingScheduler {
private LeagueService leagueService;
@Scheduled(cron = "0 0 0 * * *")
public void scheduleLeagueRankingUpdate() {
leagueService.updateRankings();
}
}
@Service
public class LeagueService {
@Transactional
public void updateRankings() {
}
}
@Scheduled 외부에서 호출@Scheduled 메서드 내부에서 @Transactional 메서드를 호출하면 트랜젝션이 올바르게 적용된다@Scheduled(cron = "0 0 0 * * *")
public void updateLeagueRankings() {
updateLeagues();
}
@Transactional
public void updateLeagues() {
}
@Transactional을 적용하려면 메서드는 public이어야한다