[TIL] 250116

MONA·2025년 1월 17일

나혼공

목록 보기
52/92

@Transactional

매일 자정에 실행되는 팀 랭킹 업데이트 기능을 구현하고 있다.
@Scheduled 어노테이션을 추가한 private 메서드에 @Transactional 어노테이션을 추가하니 다음과 같은 경고를 볼 수 있었다.

Methods annotated with '@Transactional' must be overridable

왜일까?

Spring Framework에서 @Scheduled@Transactional을 함께 사용하는 경우. Spring이 두 어노테이션을 프록시 기반으로 관리하기 때문에

@Scheduled 메서드는 프록시 객체에 의해 호출되지 않기 때문에 @Transactional이 올바르게 작동하지 않는다.

For detail

  • Spring은 프록시 기반 AOP를 사용하여 @Transactional을 처리함
  • @Scheduled는 프록시 외부에서 호출된다
    -> 동일 메서드에서 두 어노테이션을 함께 사용할 경우 @Transactional이 적용되지 않을 수 있다

@Transactional을 사용하기 위해서는 메서드가 프록시 객체를 통해 호출되어야 하고, 메서드가 public이어야 한다.
private 메서드는 프록시 객체에서 호출할 수 없기에 위와 같은 에러가 발생하는 것이다.

해결방법

  1. 메서드의 접근 제한자를 public으로 수정한다.
  • Spring의 트랜젝션 프록시가 동작할 수 있게 public으로 수정해 @Transactional을 적용한다.
@Scheduled(cron = "0 0 0 * * *")
  @Transactional
  private void updateLeagueRankings() { }
  
// 변경

@Scheduled(cron = "0 0 0 * * *")
@Transactional
public void updateLeagueRankings() { }
  1. @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() {
    }
}
  1. Transactional 메서드를 @Scheduled 외부에서 호출
  • @Scheduled 메서드 내부에서 @Transactional 메서드를 호출하면 트랜젝션이 올바르게 적용된다
@Scheduled(cron = "0 0 0 * * *")
public void updateLeagueRankings() {
    updateLeagues();
}

@Transactional
public void updateLeagues() {

}

결론

  • @Transactional을 적용하려면 메서드는 public이어야한다
profile
고민고민고민

0개의 댓글