복붙노트

[SPRING] Spring 빈에서 새로운 트랜잭션 시작하기

SPRING

Spring 빈에서 새로운 트랜잭션 시작하기

우리는 :

@Transactional(propagation = Propagation.REQUIRED)
public class MyClass implementes MyInterface { ...

MyInterface에는 go () 메소드가 있습니다.

go ()가 실행될 때 메소드가 완료되면 / 롤백을 수행하는 새 트랜잭션이 시작됩니다.

이제 우리는 MyTransactional (propagation = Propagation.REQUIRES_NEW)을 가진 MyClass에서 private 메소드를 호출한다고 가정 해 보겠습니다. Spring은 REQUIRES_NEW 주석을 "무시"하고 새로운 트랜잭션을 시작하지 않는 것으로 보입니다. 인터페이스 수준 (MyInterface)에서 작동하며 MyClass 메서드에 대한 호출을 차단하지 않습니다. 이것이 맞습니까?

go () 트랜잭션 내에서 새 트랜잭션을 시작할 수있는 방법이 있습니까? 트랜잭션이 REQUIRES_NEW로 설정된 다른 Spring 관리 Bean을 호출하는 유일한 방법은 무엇입니까?

업데이트 : 클라이언트가 클래스를 실행하지 않고 인터페이스를 참조하여 go ()를 실행할 때이를 추가합니다.

@Autowired
MyInterface impl;

impl.go();

해결법

  1. ==============================

    1.Spring 레퍼런스 2.5부터 :

    Spring 레퍼런스 2.5부터 :

    따라서 Spring은 비공개 메소드에서 @Transactional 주석을 무시합니다.

    또한,

    따라서 메서드를 public으로 만들었더라도 같은 클래스의 메서드 내에서 호출하면 새 트랜잭션이 시작되지 않습니다.

    트랜잭션 설정에서 aspectj 모드를 사용하여 트랜잭션 관련 코드가 클래스에 포함되고 런타임에 프록시가 작성되지 않도록 할 수 있습니다.

    자세한 내용은 참조 문서를 참조하십시오.

    이것을 할 수있는 또 다른 방법은 클래스 자체에서 클래스의 스프링 프록시를 가져 와서 이것보다는 메소드를 호출하는 것입니다 :

    @Service
    @Transactional(propagation = Propagation.REQUIRED)
    public class SomeService {
    
        @Autowired
        private ApplicationContext applicationContext;
    
        private SomeService  getSpringProxy() {
            return applicationContext.getBean(this.getClass());
        }
    
        private void doSomeAndThenMore() {
            // instead of
            // this.doSometingPublicly();
            // do the following to run in transaction
            getSpringProxy().doSometingPublicly();
        }
    
        public void doSometingPublicly() {
            //do some transactional stuff here
        }
    
    }
    
  2. ==============================

    2.@Transactional은 Spring AOP가 작동하는 방식 때문에 공개 메소드에있는 경우에만 주목됩니다.

    @Transactional은 Spring AOP가 작동하는 방식 때문에 공개 메소드에있는 경우에만 주목됩니다.

    그러나 원하는 경우 TransactionTemplate을 사용하여 프로그래밍 방식으로 새 트랜잭션을 시작할 수 있습니다 (예 :

    TransactionTemplate txTemplate = new TransactionTemplate(txManager);                
    txTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
    txTemplate.execute(new TransactionCallback<Object>() {
        public Object doInTransaction(TransactionStatus status) {
            // do stuff
        }
    });
    
  3. ==============================

    3.즉, 트랜잭션 동작을 달성하기 위해 프록시를 통해 메소드를 호출해야합니다. 질문에서 질문 할 때 동일한 빈에서 "REQUIRES_NEW"를 호출 할 수 있습니다. 그렇게하려면 "자기"참조를 만들어야합니다. 봄에는 그럴 수 없습니다. 너는 그것을 주입해야한다. @Resource 주석이 있습니다.

    즉, 트랜잭션 동작을 달성하기 위해 프록시를 통해 메소드를 호출해야합니다. 질문에서 질문 할 때 동일한 빈에서 "REQUIRES_NEW"를 호출 할 수 있습니다. 그렇게하려면 "자기"참조를 만들어야합니다. 봄에는 그럴 수 없습니다. 너는 그것을 주입해야한다. @Resource 주석이 있습니다.

    @Service("someService")
    public class ServieImpl implements Service {
    
       @Resource(name = "someService")
       Service selfReference;
    
       @Transactional
       public void firstMethod() {
           selfReference.secondMethod();
       }
    
       @Transactional(propagation = Propagation.REQUIRES_NEW) 
       public void secondMethod() {    
             //do in new transaction
       }
    
    } 
    

    firstMethod의 호출은 "this"가 아닌 "REQUIRES_NEW"트랜잭션이 작동하도록 프록시를 호출합니다.

  4. from https://stackoverflow.com/questions/3037006/starting-new-transaction-in-spring-bean by cc-by-sa and MIT license