[java] @Transactional 어노테이션을 어디에 넣어야합니까? 인터페이스 정의 또는 구현 클래스에서?

코드 제목의 질문 :

@Transactional (readonly = true)
public interface FooService {
   void doSmth ();
}


public class FooServiceImpl implements FooService {
   ...
}

vs

public interface FooService {
   void doSmth ();
}

@Transactional (readonly = true)
public class FooServiceImpl implements FooService {
   ...
}



답변

에서 http://static.springsource.org/spring/docs/2.0.x/reference/transaction.html

Spring 팀의 권장 사항은 @Transactional인터페이스에 주석을다는 대신 주석으로 구체적인 클래스에만 주석 을다는 것입니다. 확실히 @Transactional인터페이스 (또는 인터페이스 메서드)에 주석을 배치 할 수 있지만 이는 인터페이스 기반 프록시를 사용하는 경우에만 예상대로 작동합니다. 주석이 있다는 사실 상속되지 당신이 다음 클래스 기반의 프록시를 사용하는 경우 트랜잭션 설정은 클래스 기반의 프록시 인프라에 의해 인식되지 않고 객체는 트랜잭션 프록시에 싸여되지 않음을 의미를 (확실히 될 것이라고 나쁜 ) . 따라서 Spring 팀의 조언을 따르고 구체적인 클래스 (및 구체적인 클래스의 메서드)에만 주석을 추가하십시오 @Transactional.

참고 :이 메커니즘은 프록시를 기반으로하기 때문에 프록시를 통해 들어오는 ‘외부’메서드 호출 만 차단됩니다. 즉, ‘자체 호출’, 즉 대상 개체의 다른 메서드를 호출하는 대상 개체 내의 메서드는 호출 된 메서드가 @Transactional! 로 표시되어 있어도 런타임에 실제 트랜잭션으로 이어지지 않습니다 .

(첫 번째 문장에 강조가 추가되었으며 원본에서 다른 강조가 추가되었습니다.)


답변

인터페이스에 배치 할 수 있지만 경우에 따라 트랜잭션이 발생하지 않을 수 있다는 경고를받습니다. Spring 문서의 Secion 10.5.6 에서 두 번째 팁을 참조하십시오 .

Spring은 인터페이스에 주석을 달지 않고 @Transactional 주석으로 구체적인 클래스 (및 구체적인 클래스의 메서드)에만 주석을 달도록 권장합니다. 인터페이스 (또는 인터페이스 메소드)에 @Transactional 어노테이션을 배치 할 수 있지만 이는 인터페이스 기반 프록시를 사용하는 경우 예상 한 대로만 작동합니다. Java 주석이 인터페이스에서 상속되지 않는다는 사실은 클래스 기반 프록시 (proxy-target-class = “true”) 또는 위빙 기반 측면 (mode = “aspectj”)을 사용하는 경우 트랜잭션 설정이 다음과 같음을 의미합니다. 프록시 및 위빙 인프라에 의해 인식되지 않으며 객체가 트랜잭션 프록시에 래핑되지 않으므로 확실히 나쁠 것입니다.

이런 이유로 구현하는 것이 좋습니다.

또한 나에게 트랜잭션은 구현 세부 사항처럼 보이므로 구현 클래스에 있어야합니다. 트랜잭션 일 필요가없는 로깅 또는 테스트 구현 (모의)을위한 래퍼 구현이 있다고 상상해보십시오.


답변

Spring의 권장 사항 은 인터페이스 대신 구체적인 구현에 주석을 추가하는 것입니다. 인터페이스에서 주석을 사용하는 것은 잘못된 것이 아닙니다. 해당 기능을 오용하여 실수로 @Transaction 선언을 우회 할 수 있습니다.

인터페이스에서 트랜잭션을 표시 한 다음 스프링의 다른 곳에서 구현 클래스 중 하나를 참조하면 스프링이 생성하는 객체가 @Transactional 어노테이션을 존중하지 않는다는 것이 분명하지 않습니다.

실제로는 다음과 같이 보입니다.

public class MyClass implements MyInterface {

    private int x;

    public void doSomethingNonTx() {}

    @Transactional
    public void toSomethingTx() {}

}


답변

구체적인 클래스에서 @Transactional 지원 :

일반적으로 API, 구현 및 웹 (필요한 경우)의 3 개 섹션으로 솔루션을 설계하는 것을 선호합니다. 종속성을 최소화하여 API를 가능한 한 가볍고 / 단순 / POJO로 유지하기 위해 최선을 다합니다. API를 많이 공유해야하는 분산 / 통합 환경에서 플레이하는 경우 특히 중요합니다.

@Transactional을 넣으려면 IMHO가 효과적이지 않은 API 섹션에 Spring 라이브러리가 필요합니다. 그래서 트랜잭션이 실행되는 구현에 추가하는 것을 선호합니다.


답변

IFC의 모든 예측 가능한 구현자가 TX 데이터에 관심을 갖는 한 인터페이스에 배치하는 것은 괜찮습니다 (트랜잭션은 데이터베이스가 처리하는 문제가 아닙니다). 메소드가 TX에 대해 신경 쓰지 않는다면 (하지만 Hibernate 등을 위해 거기에 넣어야합니다), impl에 넣습니다.

또한 @Transactional인터페이스의 메소드에 배치하는 것이 조금 더 나을 수 있습니다 .

public interface FooService {
    @Transactional(readOnly = true)
    void doSmth();
}


답변