프록시 내부 호출 문제에 관한 질문 사항
보통 실무에서는
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에서 이미 트랜잭션이 걸렸기 때문에 문제가 되지 않습니다.
감사합니다.
1
안녕하세요. gaabi1204님
이 경우 mainMethod()를 호출하는 순간에 이미 트랜잭션이 적용됩니다 🙂
트랜잭션의 범위가 mainMethod()를 호출하는 순간부터 mainMethod()가 끝나서 반환 할 때 까지 적용됩니다.
따라서 mainMethod()가 호출하는 deleteMethod() 메서드 내부에서는 이미 트랜잭션이 적용된 상태로 호출되기 때문에 deleteMethod()도 같은 트랜잭션의 범위 안에 포함이 됩니다.
감사합니다.
0
안녕하세요, 인프런 AI 인턴입니다.
gaabi1204님, 프록시 내부 호출 문제와 관련해 질문해주셨네요. 먼저, 스프링의 @Transactional 어노테이션이 제대로 작동하려면 스프링이 해당 클래스의 프록시(Proxy)를 생성하여 관리해야 합니다. 이 때문에 @Transactional 어노테이션을 클래스 내부 메서드에서 직접 호출(내부 호출)하는 경우, 스프링 프록시를 거치지 않고 직접 메서드를 호출하기 때문에 트랜잭션 처리가 정상적으로 이루어지지 않을 수 있습니다.
이러한 내부 호출 문제를 해결하기 위한 방법 중 하나는, 자기 자신의 빈(Bean)을 주입받아 사용하는 것입니다. 스프링에서는 ApplicationContext를 활용하거나, @Lazy와 함께 자기 자신을 주입받아 이 문제를 해결할 수 있습니다. 예를 들어, @Autowired와 @Lazy를 이용하여 자기 자신의 빈을 주입받는 것을 통해 메서드 호출 시 스프링 컨테이너를 통해 프록시 객체를 경유하도록 할 수 있습니다.
또 다른 방법으로는 비즈니스 로직을 분리하여 별도의 클래스에 위치시키고, 이 클래스를 통해 트랜잭션을 관리하는 방법도 있습니다. 즉, 내부에서 직접 호출하는 것이 아니라 외부에서 호출할 수 있도록 구조를 변경하여, 스프링 프록시를 통해 @Transactional이 적용된 메서드를 호출하도록 하는 것입니다.
이와 같은 문제는 실무에서도 종종 발생할 수 있는 문제로, 개발자들은 이런 상황을 인지하고 적절한 방법을 선택하여 문제를 해결해야 합니다. 구체적인 구현 방법은 프로젝트의 구조나 개발 팀의 선호도에 따라 달라질 수 있습니다.
이 내용은 깊은 이해를 필요로 하며, 프로젝트의 구체적인 상황에 따라 최적의 방법이 달라지기 때문에 팀 내에서 충분한 논의가 필요할 수 있습니다.
RepositoryTest의 패키지 위치가 domain인 이유
0
29
2
REQUIRES_NEW 해결 방법에 대해서 질문있습니다!!
0
29
1
update()에 사용하는 setter 질문드립니다.
0
47
1
SQL 중심적 개발의 문제점에 대한 질문
0
72
1
혹시 Containing 을 안쓰신 이유가 있을까요?
0
83
2
[공유] 스프링부트 4.x 버전 mybatis 연동
0
173
1
@repository 어노테이션
0
89
3
ItemService
0
58
1
논리 커밋, 물리 커밋 질문드립니다.
0
54
1
내부 트랜잭션 커밋은 필수인가요?
0
57
1
프록시 커넥션 객체를 반환할 때 생성하는건가요?
0
54
1
Transaction readOnly 성능 개선 (김영한님의 대한 감사인사)
2
178
2
JPQL 대신 네이티브 쿼리를 사용해야 하는 경우
0
77
1
@EventListener(ApplicationReadyEvent.class) 관련
0
88
1
트랜잭션 동기화 매니저와 데이터 소스
0
76
1
DB 관련 강의 개설 계획은 없으신건가요?
0
133
2
물리 트랜잭션 과 논리트랜잭션 용어를 맞게 이해한걸까요
0
94
1
스프링 3 버전 이상 rollbackFor 변경된듯요
1
112
1
트랜잭션 전파 질문.
0
87
1
프로젝트 오픈 에러
0
126
1
외부 트랜잭션에서 isNewTransaction이 false로 나오는거에 대해 질문드립니다
0
83
2
같은 스레드를 사용하면 트랜잭션 동기화 매니저는 같은 커넥션을 반환
0
72
1
h2 인메모리 테스트중 예약어 충돌날 경우 대처방법
0
102
1
커스텀aop와 트랜잭션을 같이 사용할때 우선순위에 관한 질문
0
98
2





