Spring data jpa를 사용해서 다음과 같이
Controller 단에서 save() 메소드를 실행해봤다.
@RequiredArgsConstructor
@Controller
public class HomeController {
private final IdeaRepository ideaRepository;
@PostContruct
@Trasactional
public void initDummyData(){
Idea idea = new Idea();
ideaRepository.save(idea);
}
}
안 된다.
Spring은 @Trasactional은 Controller단에서 적용이 안되게 되어있다.
그런데 여기서 중요한건 @Trasactional이 Controller에서 적용되지 않는 점이 아니다.
왜 적용이 안될까? 가 중요하다.
Spring AOP는 기본적으로 다이내믹 프록시 기법을 시용해 동작하는데
다이내믹 프록시를 적용하려면 인터페이스가 필요하다.
일반적으로 Controller 클래스는 인터페이스의 구현체가 아니기 때문에
@Transactional 어노테이션이 적용이 되지 않았던 것이다.
그럼 인터페이스가 존재하지 않는 클래스에 @Transactional 어노테이션을 적용하려면...
스프링이 지원하는 클래스 프록시 모드를 사용하면된다.
클래스 프록시 모드를 사용하기 위해서는 application context파일에
트랜잭션 관련 설정을 아래와 같이 하면 된다.
<annotation-driven proxy-target-class="true"/></annotation-driven>
다만 이렇게 하는 것보다는 원래 spring 의도에 맞게 개발하는것이 맞다.
Controller 단에 @Transactional 어노테이션이 필요한 경우는
대부분 코드가 지저분하고, MVC 모델에도 맞지 않고,
클래스간의 의존성 및 중복 코딩이 여기저기 널부러져 있는 경우가 대부분이다.
따라서 리팩토링을 통해 Service 클래스에 트랜잭션
이 필요한 비지니스 로직을 작성하고,
Controller 클래스에서는 단순히 HTTP 요청에 맞게
비지니스 로직을 호출하는 구조로 변경하자.