3

How to perform rollback in Spring Data JPA for the following scenario?

Transactional
@Override
public Employee saveEmployee(EmployeeDto dto) {
    // check if EmployeeId and Department Id is present
    Employee employee = this.getByEmployeeId(dto);
    Department department = this.getByDepartmentId(dto);

    Employee employee = convertToEntity(dto, employee, department);
    employee.setEmployees(Arrays.asList(employee));
    department.setEmployees(Arrays.asList(employee));

    try {
        employee = employeeRepository.save(employee); //line-11
    } catch (DataIntegrityViolationException e) {
        throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "ConstraintViolationException", e.getCause());
    } catch (Exception ex) {
        throw new InternalServerException(HttpStatus.INTERNAL_SERVER_ERROR, env.getProperty(IConst.ERROR_DB_EXCEPTION), ex);
    }

    EmployeeEmployeeDepartment r = new EmployeeEmployeeDepartment();
    r.setId(new EmployeeDepartmentPK());
    r.setEmployee(employee);
    r.setDepartment(department);
    r.setEmployee(employee);

    try {
        compositeRepository.save(r); //line-22
    }catch (DataIntegrityViolationException e) {
        throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "ConstraintViolationException", e.getCause());
    } 
    catch (Exception ex) {
        throw new InternalServerException(HttpStatus.INTERNAL_SERVER_ERROR, env.getProperty(IConst.ERROR_DB_EXCEPTION), ex);
    }
    return employee;
}

How to roll back line-11 if line-22 fails?

Maciej Kowalski
  • 25,605
  • 12
  • 54
  • 63
PAA
  • 1
  • 46
  • 174
  • 282
  • Possible duplicate of [Roll back transaction after exception in JPA + Spring](https://stackoverflow.com/questions/5083020/roll-back-transaction-after-exception-in-jpa-spring) – SBylemans Aug 05 '19 at 12:24

2 Answers2

2

1) If ResponseStatusException and InternalServerException are both RuntimeExceptions then you do not need to do anything as Spring by default rolls back the entire transaction on any RTE.

2) Just keep in mind that invoking save() and eventually persist() on entityManager does not cause any physical update on the DB until the transaction commits. These methods simply register an entity in the Persistence Context.

Maciej Kowalski
  • 25,605
  • 12
  • 54
  • 63
  • In my case `ResponseStatusException ` extends `NestedRuntimeException` and `InternalServerException` extends `RuntimeException`. Do I need to really use transaction or not ? – PAA Aug 05 '19 at 13:03
  • You are performing save/update so you need a non-readonly transaction – Maciej Kowalski Aug 05 '19 at 13:08
  • You mean I should be using `@Transactional(readOnly = false)` – PAA Aug 05 '19 at 13:11
  • Very weird situation, when I used @Transactional, I see in debug mode, control is not coming to catch block its going somewhere and giving my own custom error and also giving long details of stack trace, why/. – PAA Aug 05 '19 at 14:05
2

Use "rollbackFor"

@Transactional(rollbackFor = DataIntegrityViolationException.class)

Multiple exception:

@Transactional(rollbackFor = { ResponseStatusException.class, InternalServerException.class })
M.Selman SEZGİN
  • 183
  • 3
  • 11
  • @M - By using this I am getting something weird exception, exception control not getting wrapped – PAA Aug 05 '19 at 14:03
  • Should I be using `@Transactional` from package `org.springframework.transaction.annotation` or package `javax.transaction` – PAA Aug 05 '19 at 14:06
  • My answer depends on Spring's package. So you can use `org.springframework.transaction.annotation.Transactional`. – M.Selman SEZGİN Aug 06 '19 at 11:31