Я использую Spring и Hibernate в одном из приложений, над которым я работаю, и у меня возникла проблема с обработкой транзакций.
У меня есть класс обслуживания, который загружает некоторые объекты из базы данных, изменяет некоторые из их значений, а затем (когда все действительно) совершает эти изменения в базе данных. Если новые значения недействительны (которые я могу проверить только после их установки), я не хочу сохранять изменения. Чтобы предотвратить Spring/Hibernate от сохранения изменений, я вызываю исключение в методе. Это приводит к следующей ошибке:
Could not commit JPA transaction: Transaction marked as rollbackOnly
И это сервис:
@Service
class MyService {
  @Transactional(rollbackFor = MyCustomException.class)
  public void doSth() throws MyCustomException {
    //load entities from database
    //modify some of their values
    //check if they are valid
    if(invalid) { //if they arent valid, throw an exception
      throw new MyCustomException();
    }
  }
}
И вот как я его вызываю:
class ServiceUser {
  @Autowired
  private MyService myService;
  public void method() {
    try {
      myService.doSth();
    } catch (MyCustomException e) {
      // ...
    }        
  }
}
То, что я ожидал бы: Никаких изменений в базе данных и никаких исключений, видимых для пользователя.
Что происходит: никаких изменений в базе данных, но приложение сбой:
org.springframework.transaction.TransactionSystemException: Could not commit JPA transaction;
nested exception is javax.persistence.RollbackException: Transaction marked as rollbackOnly
Он правильно устанавливает транзакцию на rollbackOnly, но почему сбой отката с исключением?