programing

봄 - @Transactional - 배경에서 무슨 일이 일어나나요?

goodcopy 2022. 7. 28. 22:29
반응형

봄 - @Transactional - 배경에서 무슨 일이 일어나나요?

을 붙이면 이 일어나는지 요.@Transactional

하지만 다음과 같은 의문이 든다.

  1. 봄이가 대리반을 만든다면서요?누가 이것을 좀 더 자세히 설명해 줄 수 있나요?그 프록시 클래스에는 실제로 무엇이 있습니까? 실제 수업은 어떻게 되나요? Spring이 만든 프록시 클래스를 보려면 어떻게 해야 합니까?
  2. Spring documents에서도 다음과 같이 읽었습니다.

주의: 이 메커니즘은 프록시를 기반으로 하므로 프록시를 통해 수신되는 '외부' 메서드 호출만 대행 수신됩니다.이것은 '자기 호출' 즉, 대상 객체의 다른 메서드를 호출하는 대상 객체 내의 메서드는 호출된 메서드가 다음과 같이 표시되더라도 실행 시 실제 트랜잭션으로 이어지지 않는다는 것을 의미합니다.@Transactional!

출처 : http://static.springsource.org/spring/docs/2.0.x/reference/transaction.html

외부 메서드 호출만 트랜잭션 아래에 있고 자기 호출 메서드는 아닌 이유는 무엇입니까?

이건 큰 화제입니다.스프링 레퍼런스 문서는 여러 장으로 구성되어 있습니다.Spring의 선언적 트랜잭션 지원은 AOP를 기반으로 하므로 Aspect-Oriented Programming and Transactions에 대한 내용을 읽어보기를 권장합니다.

하지만 매우 높은 수준에서, 스프링은 다음을 선언하는 클래스를 위한 프록시를 만듭니다.@Transactional수업 자체나 멤버들에게요.프록시는 실행 시 대부분 보이지 않습니다.Spring은 프록시 중인 오브젝트에 메서드 호출의 전, 후 또는 그 주위의 동작을 삽입할 수 있습니다.트랜잭션 관리는 관련될 수 있는 동작의 한 예에 불과합니다.보안 검사는 또 다른 문제입니다.또한 로그 기록과 같은 용도로도 사용자 고유의 정보를 제공할 수 있습니다. 어떤 을 붙일 때,@TransactionalSpring은 주석을 다는 클래스와 동일한 인터페이스를 구현하는 프록시를 동적으로 만듭니다.클라이언트가 오브젝트에 콜을 발신하면 콜이 대행 수신되어 프록시 메커니즘을 통해 동작이 주입됩니다.

참고로 EJB의 트랜잭션도 이와 유사합니다.

관찰한 바와 같이 프록시 메커니즘은 외부 객체에서 콜이 착신했을 때만 기능합니다.를 할 을 하는 것입니다.this참조: 프록시를 바이패스합니다.그러나 그 문제를 해결할 방법은 여러 가지가 있다.포럼 투고에서 가 사용하는 접근법에 대해 설명하겠습니다.BeanFactoryPostProcessor실행 시 프록시 인스턴스를 "셀프 소싱" 클래스에 주입합니다.이 참조를 다음 멤버 변수에 저장합니다.me해야 할 " " " " " " " " " " " " " )를 me.someMethod()대해 설명하고 있습니다)의 약칭입니다.

에 주의:BeanFactoryPostProcessor코드는 봄 1.x 기간으로 다시 작성되었기 때문에 지금은 조금 다를 것입니다.하지만 그게 너에게 아이디어를 주길 바라.업데이트 버전이 있어서 이용할 수중에 있을 것 같습니다.

하여 봄콩을 되어 있는 @Transactional주석을 사용하면 실제 콩 주위에 프록시 오브젝트가 생성됩니다.이러한 프록시 개체는 런타임에 자동으로 생성되는 클래스의 인스턴스입니다.메서드가 호출될 때 이러한 프록시 개체의 기본 동작은 "target" bean(즉, bean)에서 동일한 메서드를 호출하는 것입니다.

할 수 .이러한 는 타겟빈의에 프록시에 됩니다.이러한 인터셉터가 존재할 경우 타겟빈의 메서드를 호출하기 전에 프록시에 의해 호출됩니다.는, 「 」라고 코멘트가 붙어 있습니다.@Transactional에는, 「」, 「」가 됩니다.TransactionInterceptor이치노코드에서 에서 메서드를 이 경우 됩니다.이것에 의해, 우선, 클라이언트 코드에서 메서드가 호출됩니다.TransactionInterceptor(트랜잭션을 시작합니다).이것에 의해, 타겟 빈의 메서드가 기동됩니다.되면, 「」는TransactionInterceptor트랜잭션을 커밋/백백합니다.이치노

「외부 메서드」에 대해서는, 사용의 빈이 독자적인 메서드 중 하나를 호출했을 경우는, 프록시를 개입시켜 기동하지 않습니다.봄은 당신의 콩을 대신 싸는다는 것을 기억하라. 당신의 콩은 그것에 대해 전혀 알지 못한다.외부로부터의 전화만이 프록시를 경유합니다.

도움이 되셨어요?

시각적인 사람으로서, 저는 프록시 패턴의 시퀀스 다이어그램에 관여하는 것을 좋아합니다. 첫 글자를 .ClientProxy.method().

  1. 클라이언트는 자신의 관점에서 타깃에 메서드를 호출하고 프록시에 의해 묵묵히 차단됩니다.
  2. before 측면이 정의되어 있는 경우 프록시는 이를 실행합니다.
  3. 그리고 실제 방법(대상)을 실행한다.
  4. 애프터 리턴과 애프터 슬로우는 메서드가 반환된 후 및/또는 메서드가 예외를 발생시킨 경우 실행되는 옵션입니다.
  5. 그 후 프록시는 애프터 애스펙트(정의되어 있는 경우)를 실행합니다.
  6. 마지막으로 프록시는 발신측 클라이언트로 돌아갑니다.

프록시 패턴 시퀀스 다이어그램(출처를 말하는 조건으로 사진을 게재할 수 있었습니다.작성자:Noel Vaes, 웹사이트: https://www.noelvaes.eu)

가장 간단한 답은 다음과 같습니다.

@Transactional트랜잭션의 경계는 메서드가 완료되면 시작되고 경계는 종료됩니다.

JPA 콜을 사용하는 경우 모든 커밋은 이 트랜잭션 경계에 있습니다.

entity1, entity2 및 entity3을 저장한다고 가정합니다.여기서 entity3 저장 중 예외가 발생하며 enitiy1과 entity2가 동일한 트랜잭션으로 들어오기 때문에 entity1과 entity2가 entity3과 함께 롤백됩니다.

트랜잭션:

  1. 엔티티1절약하다
  2. 엔티티2절약하다
  3. 엔티티3절약하다

모든 예외는 DB와의 모든 JPA 트랜잭션을 롤백합니다.내부적으로 JPA 트랜잭션은 Spring에서 사용됩니다.

기존의 답은 모두 맞지만, 이 복잡한 주제만을 제시할 수는 없다고 생각합니다.

포괄적이고 실용적인 설명은 이 Spring @Transactional Indepth 가이드를 참조해 주십시오.이 가이드는, 다수의 코드 예시와 함께, 최대 4,000개의 간단한 단어로 트랜잭션 관리를 다루고 있습니다.

늦은 감이 있지만, 프록시(프록시를 통해 들어오는 외부 메서드 콜만 대행 수신됨)에 대한 당신의 우려를 잘 설명해 주는 것을 발견했습니다.

예를 들어 다음과 같은 클래스가 있습니다.

@Component("mySubordinate")
public class CoreBusinessSubordinate {

    public void doSomethingBig() {
        System.out.println("I did something small");
    }

    public void doSomethingSmall(int x){
        System.out.println("I also do something small but with an int");    
  }
}

그리고 다음과 같은 측면이 있습니다.

@Component
@Aspect
public class CrossCuttingConcern {

    @Before("execution(* com.intertech.CoreBusinessSubordinate.*(..))")
    public void doCrossCutStuff(){
        System.out.println("Doing the cross cutting concern now");
    }
}

다음과 같이 실행할 경우:

 @Service
public class CoreBusinessKickOff {

    @Autowired
    CoreBusinessSubordinate subordinate;

    // getter/setters

    public void kickOff() {
       System.out.println("I do something big");
       subordinate.doSomethingBig();
       subordinate.doSomethingSmall(4);
   }

}

상기 코드의 호출 킥오프 결과.

I do something big
Doing the cross cutting concern now
I did something small
Doing the cross cutting concern now
I also do something small but with an int

하지만 코드를 바꾸면

@Component("mySubordinate")
public class CoreBusinessSubordinate {

    public void doSomethingBig() {
        System.out.println("I did something small");
        doSomethingSmall(4);
    }

    public void doSomethingSmall(int x){
       System.out.println("I also do something small but with an int");    
   }
}


public void kickOff() {
  System.out.println("I do something big");
   subordinate.doSomethingBig();
   //subordinate.doSomethingSmall(4);
}

메서드는 내부적으로 다른 메서드를 호출하므로 인터셉트되지 않고 다음과 같이 출력됩니다.

I do something big
Doing the cross cutting concern now
I did something small
I also do something small but with an int

이렇게 하면 우회할 수 있습니다.

public void doSomethingBig() {
    System.out.println("I did something small");
    //doSomethingSmall(4);
    ((CoreBusinessSubordinate) AopContext.currentProxy()).doSomethingSmall(4);
}

코드 스니펫은 https://www.intertech.com/Blog/secrets-of-the-spring-aop-proxy/ 에서 가져옵니다.

언급URL : https://stackoverflow.com/questions/1099025/spring-transactional-what-happens-in-background

반응형