😅서론
상속받은 클래스 내에 @Transactonal 이 걸려있는 삭제 메소드가 트랜잭션이 발동을 안 하는 버그를 발견했다.
같은 클래스 내에서 프록시가 발동하지 않는다는 것은 알고 있었지만, 막상 겪으니 다른 클래스인데 뭐가 문제지..?
란 생각에 빠져서 찾는 대에 시간을 좀 사용했다..
그 김에 작성..
😁본론
스프링은 AOP를 하기위해 기본적으로 디자인패턴인 프록시패턴을 채택하여 사용하고 있다.
AOP(Aspect Oriented Programming)
관점지향 프로그래밍이라는 뜻으로 여러 곳에서 사용되는 공통된 로직을 모듈화하여
비즈니스 로직에서 분리시켜준다.
이로써 우리는 비즈니스 로직 외에 부가적인 로직은 따로 외부에서 관리하여 유지보수 및 재사용성이 용이해진다.
프록시(Proxy)
스프링의 AOP는 프록시를 활용하여 구현을 하고있다.
어떠한 클래스가 AOP 대상일 시 원본 클래스 대신 프록시가 감싸진 클래스가 자동으로 만들어져
프록시 클래스가 빈에 등록이 된다.
이렇게 빈에 등록된 프록시 클래스는 원본 클래스가 호출될 시 자동으로 바꿔서 사용해준다.
내가 이해한 바로는 약간 이런 느낌이다.
외부메소드인 C에서 A메소드를 호출할 시 프록시가 감싸져있는 A메소드를 호출하게 된다.
반면, 내부 메소드인 B메소드에서 A메소드를 호출할 시 Proxy를 호출하게 되는 게 아닌
직접적으로 A메소드를 호출하여 프록시가 발동하지 못하게 된다.
😣이로인한 문제점
위와 같이 saveUser를 통한 this.save 호출 시 @Transactional이 동작하지 않는다.
🤨그럼 어떻게 해결해야할까?
1. 의존성 주입
인터넷에 가장 많이 나오는 방법으로 의존성주입을 통해 프록시로 감싸진 서비스를 받아와서
받아온 프록시 클래스를 호출하는 방식이다.
이 방식은 추천하지 않는다.
2. 상위 메소드에 @Transactional 걸기
위에 서론에서 얘기했던 문제를 해결했던 방법이다.
어차피 saveUser도 다른 서비스, 혹은 컨트롤러에서 호출을 해온다.
이렇게 saveUser에 트랜잭션을 걸게되면 save 트랜잭션이 아닌 saveUser에 있는 트랜잭션이
걸리기 때문에 트랜잭션은 발동이 된다.
save에서만 다른 옵션을 통해 트랜잭션을 주고 싶은 경우에는 이 방법으로는 안된다.
3. 상위 메소드 분리
당연하게 써야하고, 가장 맞는 방법이라고 생각한다.
프록시 클래스를 외부 클래스에서 호출하는 방식이다.
왠만해서는 이 방식을 사용하도록 하자.
'JVM > Spring' 카테고리의 다른 글
[SPRING] AOP 우선순위 설정하기. (2) | 2021.08.14 |
---|---|
[SPRING] @Transactional (트랜잭션) 강제 롤백 (0) | 2021.07.25 |
[SPRING] feign은 뭘까? (0) | 2021.04.18 |
[SPRING]@Transactional Annotation 알고 쓰자 (0) | 2021.04.17 |
[SPRING] lombok 활용 (0) | 2020.12.27 |