인프런 커뮤니티 질문&답변

gaabi1204님의 프로필 이미지
gaabi1204

작성한 질문수

스프링 DB 2편 - 데이터 접근 활용 기술

프록시 내부 호출 문제에 관한 질문 사항

해결된 질문

작성

·

162

·

수정됨

1

보통 실무에서는

controller ->service(interface) -> repository -> dao

^

|

serviceImpl (service Interface 구현체)

이렇게 많이 사용합니다.

 

제가 개발자로 실무를 하지 않아서 정확하지는 않지만

@Configuratiain 을 이용한 클래스에서 구성을 잡고 포인트컷으로 지정된 패키지와 그 하위 *Impl 메서드에 모든 @Transaction 어노테이션이 적용되도록 설정을 했던 것 같습니다.

그리고 serviceImpl에서 @Transactional 어노테이션을 사용하지 말라고 가이드가 내려 옵니다.

 

코딩은

public class serviceImpl {

public int createMember(MemberVO member) {

deleteMember(member);

insertMember(member);

updateMember(member);

}

 

public int deleteMember(MemberVO member) {

//비지니스 로직 수행

String id = member.getId(); //null 체크 되어 있다고 가정

repository.delete(id);

}

public int insertMember(MemberVO member) {

//비지니스 로직 수행

repository.insert(member);

}

 

public int updateMember(MemberVO member) {

//비지니스 로직 수행

repository.update(member);

}

}

 

그런데 한번도 아키텍처나 업무 공통 단에서 내부 호출에 대한 가이드가 없었습니다.

그리고 실제로 내부 호출을 해도 Transaction 처리에 문제가 있지는 않았습니다.

그렇다고 AspectJ 의 컴파일러를 이용하는 것 같지도 않고

ObjectProvider를 사용하는 것 같지도 않는데 말입니다.

 

고급편에서도 궁금했지만 DB2편을 다 수강하고 나서 질문을 드립니다

 

아키텍처 쪽에서 내부 호출에 대한 문제를 모르진 않았을것 같은데

통상적으로 어떻게 @Transactional 처리를 하기에 개발자들은 내부 호출 문제에 신경 쓰지 않을까요?

 

 

 

 

 

 

 

답변 2

1

김영한님의 프로필 이미지
김영한
지식공유자

안녕하세요. gaabi1204님

@Transaction을 클래스 레벨에 걸거나, 또는 말씀하신 것 처럼 걸게되면 외부에서 서비스를 호출하는 시점에 바로 트랜잭션이 걸리게 됩니다.

따라서 외부 클래스에서 createMember를 호출할 때도 트랜잭션이 걸리고, 따라서 외부 클래스에서 deleteMember를 호출할 때도 트랜잭션이 걸리게 됩니다.

예를 들어서 createMember를 호출하고 그 안에서 내부 메서드를 호출해도 createMember에서 이미 트랜잭션이 걸렸기 때문에 문제가 되지 않습니다.

감사합니다.

김영한님의 프로필 이미지
김영한
지식공유자

안녕하세요. gaabi1204님

이 경우 mainMethod()를 호출하는 순간에 이미 트랜잭션이 적용됩니다 🙂

트랜잭션의 범위가 mainMethod()를 호출하는 순간부터 mainMethod()가 끝나서 반환 할 때 까지 적용됩니다.

 

따라서 mainMethod()가 호출하는 deleteMethod() 메서드 내부에서는 이미 트랜잭션이 적용된 상태로 호출되기 때문에 deleteMethod()도 같은 트랜잭션의 범위 안에 포함이 됩니다.

감사합니다.

0

안녕하세요, 인프런 AI 인턴입니다.

gaabi1204님, 프록시 내부 호출 문제와 관련해 질문해주셨네요. 먼저, 스프링의 @Transactional 어노테이션이 제대로 작동하려면 스프링이 해당 클래스의 프록시(Proxy)를 생성하여 관리해야 합니다. 이 때문에 @Transactional 어노테이션을 클래스 내부 메서드에서 직접 호출(내부 호출)하는 경우, 스프링 프록시를 거치지 않고 직접 메서드를 호출하기 때문에 트랜잭션 처리가 정상적으로 이루어지지 않을 수 있습니다.

이러한 내부 호출 문제를 해결하기 위한 방법 중 하나는, 자기 자신의 빈(Bean)을 주입받아 사용하는 것입니다. 스프링에서는 ApplicationContext를 활용하거나, @Lazy와 함께 자기 자신을 주입받아 이 문제를 해결할 수 있습니다. 예를 들어, @Autowired@Lazy를 이용하여 자기 자신의 빈을 주입받는 것을 통해 메서드 호출 시 스프링 컨테이너를 통해 프록시 객체를 경유하도록 할 수 있습니다.

또 다른 방법으로는 비즈니스 로직을 분리하여 별도의 클래스에 위치시키고, 이 클래스를 통해 트랜잭션을 관리하는 방법도 있습니다. 즉, 내부에서 직접 호출하는 것이 아니라 외부에서 호출할 수 있도록 구조를 변경하여, 스프링 프록시를 통해 @Transactional이 적용된 메서드를 호출하도록 하는 것입니다.

이와 같은 문제는 실무에서도 종종 발생할 수 있는 문제로, 개발자들은 이런 상황을 인지하고 적절한 방법을 선택하여 문제를 해결해야 합니다. 구체적인 구현 방법은 프로젝트의 구조나 개발 팀의 선호도에 따라 달라질 수 있습니다.

이 내용은 깊은 이해를 필요로 하며, 프로젝트의 구체적인 상황에 따라 최적의 방법이 달라지기 때문에 팀 내에서 충분한 논의가 필요할 수 있습니다.

gaabi1204님의 프로필 이미지
gaabi1204

작성한 질문수

질문하기