UnexpectedRollbackException в классе @Transactional, когда метод помечен noRollback для брошенного исключения - PullRequest
0 голосов
/ 16 апреля 2020

У меня есть помеченный @Transactional класс FooServiceImpl, который должен заполнить объект FooDetails значениями, полученными из другого класса @Transactional BarServiceImpl.

При попытке получить значения из BarServiceImpl выбрасывается исключение 1. Я хотел бы оставить поле FooDetails, установщик которого выбросил исключение, и перехватить исключение. Все остальные поля должны оставаться заполненными, даже если какой-то установщик выдал исключение.

К сожалению, это не так, потому что транзакция была помечена как только для отката из-за того, что было сгенерировано Exception1, хотя я явно пометил метод как "noRollbackFor = Exception1.class" и перехватил исключение.

Почему это происходит и как я могу исправить код, чтобы заполнить все поля, чьи установщики не генерировали исключение, и оставить пустыми те, чьи установщики бросили одно. Вот код, который приводит к поведению:

@Service
@Transactional
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface TransactionalService {
    // The name of the service
    String value() default "";
}

public class FooDetails {
    private String fieldA;
    private String fieldB;

    // getters and setters
    ...
}

@TransactionalService 
public class BarServiceImpl implements BarService {
    @Override
    public String getFieldB() throws Exception1 {
        ...
        try {
            ...
        } catch (Exception2 e2) {
            ...
            throw new Exception1();
        } catch (Exception3 e3) {
            ...
            throw new Exception1();
        }
    }
}

@TransactionalService 
public class FooServiceImpl implements FooService {
    ...
    ...

    @Autowired BarService barService;

    @Override
    @Transactional(noRollbackFor = {Exception1.class, Exception2.class, Exception3.class})
    public FooDetails getFooDetails(Long fooId) {
        Foo foo = fooDao.get(fooId);
        if (foo == null) {
            return null;
        }

        FooDetails fooDetails = new FooDetails();

        // getAFooDetails() has no exceptions to throw => ok
        fooDetails.setFieldA(getAFooDetails());

        // barService.getFieldB() throws an Exception1 => results in 
        // "org.springframework.transaction.UnexpectedRollbackException:
        //           Transaction rolled back because it has been marked as rollback-only" => all foo fields left empty
        try {
            fooDetails.setFieldB(barService.getFieldB());
        } catch (Exception1 e) {
            LOG.info(e.getMessage());
        }        
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...