
클라이언트가 @Transactional(클래스나 메소드에 하나라도 붙어 있어야함)이 붙어있는 클래스를 의존관계 주입을 받으면 basicService$$EnhancerBySpringCGLIB...과 같은 프록시 클래스가 대신 의존관계주입이 된다.
프록시 클래스가 주입될 수 있는 이유는 스프링 컨테이너에는 실제 객체 대신에 프록시가 스프링 빈으로 등록되어 있기 때문이다.
그리고 프록시 클래스는 실제 클래스를 참조하고 있다.


만약 해당 메소드가 트랜잭션 적용 대상이라면 프록시 클래스는 트랜잭션을 시작한 다음 실제 클래스의 서비스 로직을 실행하고 서비스 로직이 끝난다면 다시 프록시 클래스로 넘어와 트랜잭션 로직을 커밋하거나 롤백해서 트랜잭션을 종료한다.
하지만 트랜잭션 적용대상이 아닌 메소드를 실행한다면 트랜잭션을 시작하지 않고 실제 클래스의 서비스를 실행하고 끝낸다.
@Transactional을 통해 트랜잭션을 실행시키려면 프록시를 통해 호출해야 트랜잭션이 적용된다.
만약 프록시를 거치지 않고 대상 객체를 직접 호출하게 되면 AOP가 적용되지 않고, 트랜잭션도 적용되지 않는다.

대상 객체의 내부에서 메서드 호출이 발생하면 프록시를 거치지 않고 대상 객체를 직접 호출하는 문제가 발생한다.
이렇게 되면 @Transactional 이 있어도 트랜잭션이 적용되지 않는다.
그럴 땐 내부호출 하는 메소드를 별도의 클래스로 분리시키면 해결된다.

@Transactional은 public 메소드에만 적용이 되고 나머지 private, protected 등등.. 은 Transactional을 붙여도 적용되지 않는다.
@Transactional은 기본적으로 runtimeException은 롤백하고 checkedException은 커밋한다.
그 이유는 runtimeException은 개발자가 예상하지 못해 대응하지 못하지만. checkedException은 개발자가 의도적으로 낼 수 있기 때문에 실패하면 처리로직을 다시 실행할 수 있기 때문이다.
rollbackFor 옵션을 사용해서 원하는 예외가 발생하면 롤백 시키도록 지정할 수도 있다.
그런 기준은 개발자가 상황에 따라서 유동적으로 바꾸면 된다.
@Transactional은 별 생각 없이 의도적으로 붙였는데 공부를 하고 나니 새로운 면을 알게되었다. 특히 프록시 클래스를 사용하다는 사실은 처음 알았고 놀랬다...
또 공부하러 가야지~