Transaction Rollback is not heppening when error occour in nested method

595 Views Asked by At

In my recent project I faced a scenario where I need to rollback database operation when error happen in nested method. Earlier I worked with @Transactional on single method. That time it worked fine. But in current scenario I have dependency on another method. So I need to rollback when error happen is nested method. I want to rollback in this method

@Transactional
@Override
public String updateCustomOfficeHour(OfficeHour officeHour) {
    if (officeHour.getId() == null || officeHourRepository.getFirstById(officeHour.getId()) == null)
        throw new EntityNotFoundException("No Office-Hour found with this id");

    OfficeHour temp = officeHourRepository.getFirstById(officeHour.getId());
    List<OfficeHour> officeHours = officeHourRepository.findByFromDateAndToDate(temp.getFromDate(), temp.getToDate());

    List<OfficeHour> tempList = new ArrayList<>();
    for (OfficeHour officeHourObj : officeHours) {
        officeHourObj.setDeleted(true);
        tempList.add(officeHourObj);
    }
    officeHourRepository.saveAll(tempList);
    this.createCustomOfficeHour(officeHour);
    return "Updated Custom-Office-Hour";
}

Here I have a database operation in line officeHourRepository.saveAll(tempList); I need to rollback when error occur in method this.createCustomOfficeHour(officeHour);. This method is

   @Transactional
    @Override
    public String createCustomOfficeHour(OfficeHour officeHour) {
        if (officeHour.getFromDate() == null || officeHour.getToDate() == null
                || officeHour.getFirstOutTime() == null || officeHour.getLastInTime() == null
                || officeHour.getInTime() == null || officeHour.getOutTime() == null)
            throw new EntityNotFoundException("Null value received for OfficeHour fields!");

        if (officeHour.getToDate().compareTo(officeHour.getFromDate()) < 0)
            throw new EntityNotFoundException("FromDate is Getter than ToDate");

        if (officeHourRepository.isFromDateExist(officeHour.getFromDate()).longValue() > 0
                || officeHourRepository.isToDateExist(officeHour.getToDate()).longValue() > 0) {
            throw new EntityNotFoundException("FromDate/ToDate is already assigned");
        }

        if (officeHourRepository.isDateExistsBetweenFromAndToDate(officeHour.getFromDate(), officeHour.getToDate()).longValue() > 0)
            throw new EntityNotFoundException("Office Hour Already Assigned In This Range");


        for (int i = 1; i <= count; i++) {
           ........
           ........
           ........
           officeHourRepository.save(obj);

        }
        return "Custom Office-Hour Created";
    }

And this is my Exception class

public class EntityNotFoundException extends RuntimeException {

    public EntityNotFoundException(String message) {
        super(message);
    }
}

I have also added spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL5InnoDBDialect in application.properties

Any help will be appreciated.

1

There are 1 best solutions below

5
Maciej Kowalski On

Your EntityNotFoundException is a non-checked exception and following the spring docs:

Spring default behavior for declarative transaction management follows EJB convention (roll back is automatic only on unchecked exceptions)

the transaction should be rolled back by default.

This is because updateCustomOfficeHour and createCustomOfficeHour are processed under same transaction (there is no override of propagation here so the default REQUIRED is used).

You could add an explicit rollback for your exception on the updateCustomOfficeHour method but that should be redundant anyway:

@Transactional(rollbackFor = {EntityNotFoundException.class})