복붙노트

[SPRING] 왜 트랜잭션은 RuntimeException에서 롤백하지만 SQLException은 그렇지 않다.

SPRING

왜 트랜잭션은 RuntimeException에서 롤백하지만 SQLException은 그렇지 않다.

Spring에서 관리하는 서비스 메소드를 사용하여 데이터베이스 삽입을 관리합니다. 여러 개의 insert 문이 있습니다.

@Transactional
public void insertObservation(ObservationWithData ob) throws SQLException 
{
    observationDao.insertObservation(ob.getObservation());
            // aop pointcut inserted here in unit test
    dataDao.insertData(ob.getData());
}

두 번째 삽입을 호출하기 전에 예외를 throw하는 두 개의 단위 테스트가 있습니다. 예외가 RuntimeException이면 트랜잭션이 롤백됩니다. 예외가 SQLException 인 경우 첫 번째 삽입이 지속됩니다.

나는 당황 스럽다. 누구나 트랜잭션이 SQLException에 롤백되지 않는 이유를 말해 줄 수 있습니까? 누구든지 이것을 관리하는 방법을 제안 할 수 있습니까? 나는 SQLException을 잡아서 RuntimeException을 던질 수 있지만, 그것은 이상하게 보입니다.

해결법

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

    1.이것은 정의 된 동작입니다. 문서에서 :

    이것은 정의 된 동작입니다. 문서에서 :

    이는 모든 Spring 트랜잭션 API에서 공통된 동작이다. 기본적으로 트랜잭션 코드 내에서 RuntimeException이 throw되면 트랜잭션이 롤백됩니다. 체크 된 예외 (RuntimeException이 아닌)가 발생하면 트랜잭션은 롤백되지 않습니다.

    이 배후의 이론적 근거는 RuntimeException 클래스는 일반적으로 복구 할 수없는 오류 조건을 나타 내기 위해 Spring에 의해 사용된다는 것입니다.

    원하는 경우이 동작을 기본값에서 변경할 수 있습니다. 그러나이를 수행하는 방법은 Spring API 사용 방법과 트랜잭션 관리자 설정 방법에 따라 다릅니다.

  2. ==============================

    2.Spring은 RuntimeExceptions (DataAccessExceptions를 사용하여 SQLExceptions 또는 ORM의 예외를 래핑하는 것을 포함)를 광범위하게 사용하여 예외로부터 복구가없는 경우를 대비합니다. 그것은 서비스 위의 레이어가 어떤 것을 알 필요가 있지만 트랜잭션이 방해 받기를 원하지 않는 경우에 체크 된 예외를 사용하기를 원한다고 가정합니다.

    Spring은 RuntimeExceptions (DataAccessExceptions를 사용하여 SQLExceptions 또는 ORM의 예외를 래핑하는 것을 포함)를 광범위하게 사용하여 예외로부터 복구가없는 경우를 대비합니다. 그것은 서비스 위의 레이어가 어떤 것을 알 필요가 있지만 트랜잭션이 방해 받기를 원하지 않는 경우에 체크 된 예외를 사용하기를 원한다고 가정합니다.

    Spring을 사용하고 있다면 jdbc-wrapping 라이브러리와 DataAccessException 번역 기능을 사용할 수도 있습니다. 유지 보수해야 할 코드의 양이 줄어들고보다 의미있는 예외를 제공합니다. 구현 특정 예외를 throw하는 서비스 계층을 갖는 것도 나쁜 냄새입니다. 사전 스프링 방식은 구현 특정 예외를 래핑하는 구현에 독립적 인 검사 예외를 작성하는 것이 었습니다. 이로 인해 많은 작업량과 비 대한 코드 기반이 발생했습니다. 봄의 길은 그러한 문제를 피한다.

    이런 식으로 Spring을 선택하게 된 이유를 알고 싶다면 아마도 AOP를 사용하여 트랜잭션 처리를 추가하기 때문일 것입니다. 래핑하는 메소드의 서명을 변경할 수 없으므로 검사 된 예외는 옵션이 아닙니다.

  3. ==============================

    3.@Transactional의 경우 기본적으로 롤백은 런타임에 대해 발생하며 체크되지 않은 예외 만 발생합니다. 따라서, 체크 된 예외 SQLException은 트랜잭션의 롤백을 트리거하지 않습니다. rollbackFor 및 noRollbackFor 주석 매개 변수를 사용하여 동작을 구성 할 수 있습니다.

    @Transactional의 경우 기본적으로 롤백은 런타임에 대해 발생하며 체크되지 않은 예외 만 발생합니다. 따라서, 체크 된 예외 SQLException은 트랜잭션의 롤백을 트리거하지 않습니다. rollbackFor 및 noRollbackFor 주석 매개 변수를 사용하여 동작을 구성 할 수 있습니다.

    @Transactional(rollbackFor = SQLException.class)
    public void insertObservation(ObservationWithData ob) throws SQLException 
    {
        observationDao.insertObservation(ob.getObservation());
                // aop pointcut inserted here in unit test
        dataDao.insertData(ob.getData());
    }
    
  4. from https://stackoverflow.com/questions/7125837/why-does-transaction-roll-back-on-runtimeexception-but-not-sqlexception by cc-by-sa and MIT license