복붙노트

[SPRING] @Transactional 내부의 try-catch에서 변경 사항을 커밋하십시오.

SPRING

@Transactional 내부의 try-catch에서 변경 사항을 커밋하십시오.

내가 몇 가지 물건을하고 ActiveRecord 패턴 스타일에서 메커니즘을 로깅을 고려하십시오 :

@Transactional
public void doSmt() {
    try {
        someOperation(); // can throw exception
        Logger.logIntoDb(); // if everything is OK
    } catch {Exception e} {
        Logger.logIntoDbWithException(e.getMessage()); // log error into db

        throw new MyCustomException(e);
    }
}

public static void logIntoDbWithException(String message) {
    final LogEntry logEntry = new LogEntry();
    logEntry.setDate(new Date());
    logEntry.setMessage(message);
    logEntry.persist();
}

실패의 경우 오류 메시지를 유지하고 싶지만 catch 절에서 예외를 다시 발생 시키려면 트랜잭션이 롤백되고 LogEntry는 유지되지 않습니다. 내가 보는 유일한 방법은 수동으로 flush ()를 persist () 이후에 호출하는 것이다.

이 작업을 수행하는 더 깨끗한 솔루션이 있습니까?

감사.

UPD :

나는 지속성을 수행하는 정적 메소드를 가지고 있기 때문에 받아 들인 대답에 다음과 같은 해킹을 적용해야합니다.

public static void logIntoDbWithException(String message) {
    new Runnable() {
        @Transactional(propagation = Propagation.REQUIRES_NEW)
        public void run() {
            final LogEntry logEntry = new LogEntry();
            logEntry.setDate(new Date());
            logEntry.setMessage(message);
            logEntry.persist();
        }
    }.run();
}

해결법

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

    1.첫째, flush ()를 호출해도 아무 것도 할 수 없습니다. flush ()는 아무 것도 저 지하지 않으며 동일한 트랜잭션에서 오류를 로깅 할 때 삽입이 롤백됩니다.

    첫째, flush ()를 호출해도 아무 것도 할 수 없습니다. flush ()는 아무 것도 저 지하지 않으며 동일한 트랜잭션에서 오류를 로깅 할 때 삽입이 롤백됩니다.

    따라서 오류를 기록하려면 새로운 '중첩 된'트랜잭션을 시작해야합니다.

    public class A {
    
        @Autowired
        private B b;
    
        @Transactional
        public void doSmt() {
            try {
                someOperation(); // can throw exception
                b.logIntoDb(); // if everything is OK
            } catch {Exception e} {
                b.logIntoDbWithException(e.getMessage()); // log error into db
    
                throw new MyCustomException(e);
            }
        }
    }
    
    public class B{
    
        //outer transaction is still active
        public  void logIntoDb(String message) {
            final LogEntry logEntry = new LogEntry();
            logEntry.setDate(new Date());
            logEntry.setMessage(message);
            logEntry.persist();
        }
    
        // 'outer' transaction will be suspended until this method completes
        // this new transaction will commit/rollback independently of the outer transaction
        @Transactional(propagation = Propagation.REQUIRES_NEW)
        public  void logIntoDbWithException(String message) {
            final LogEntry logEntry = new LogEntry();
            logEntry.setDate(new Date());
            logEntry.setMessage(message);
            logEntry.persist();
        }
    }
    
  2. from https://stackoverflow.com/questions/36908407/commit-changes-in-try-catch-inside-transactional by cc-by-sa and MIT license