0

I have a case where I need to initiate calls to four different services in the same method. According to our business logic all four steps must succeed, rollback otherwise. The problem is that since all the steps occur in the same transaction (via @Transactional annotation) the second call in the method cant process the result of the first one. I have tried Propagation.REQUIRES_NEW on the first call but since it starts a new transaction the changes it makes are committed and not rollbacked whether the other calls succeed or not. At some point it seemed like Propagation.NESTED could do the work but I get a NestedTransactionNotSupportedException which warns me of setting the nestedTransactionAllowed property to true. But I could not found any document about how to do that. Any ideas? And also would appreciate any other suggestion for the problem. Thanks.

Root method:

@Override
    @Transactional
    public GuestUserDto createGuestUser(GuestUserRegisterRequest existingGuestUser) {
        guestUserDeactivationDelegateService.deactivateGuestUser(existingGuestUser);

        UserDto userDto = guestUserRegistrationDelegateService.registerGuestUser(
            guestUserRegisterDtoConverter.convert(existingGuestUser));

        createGuestUserAddress(existingGuestUser);

        guestUserRegisterHistoryService.createRegisterHistory(
            guestUserRegistrationHistoryDtoBuilder.build(userDto.getMemberId(), existingGuestUser));

        return guestUserDtoConverter.convert(userDto);
    }

Deactivation method:

    @Transactional
    public void deactivateGuestUser(GuestUserRegisterRequest existingUser) {
        deactivateSmsVerification(existingUser.getMemberId());
        
        String emailPlaceholder = existingUser.getMemberId() + existingUser.getEmail();
        userGraphClientService.updateUserStatus(createUserRequest(existingUser.getMemberId()));

        updateGuestUserStatus(existingUser.getMemberId(), emailPlaceholder);
    }
  • 1
    Everything in the same transaction should be able to see the data not yet committed, so what you describe should just work. So unless you are doing something strange (which is what I suspect) this should just work. – M. Deinum Jan 04 '22 at 13:37
  • First method nullifies a email field in DB and the second saves another entity with the previous email. But the second method keeps throwing EmailAlreadyExists exception. It works just fine when I put REQUIRES_NEW on the first method but then when I have it fail at some later step like 3rd or 4th, all rollbacks except the first method's operation. – Erhan Cavdar Jan 04 '22 at 14:07
  • Please don't describe your code, instead show your code. – M. Deinum Jan 04 '22 at 14:34
  • Edited the question. – Erhan Cavdar Jan 05 '22 at 05:51

2 Answers2

0

Seems that the main cause was Hibernate's flush operations order, as it was giving priority to insert over update. Flushing manually after updating in DAO layer solved the problem.

0

NestedTransactionAllowed can be set in HibernateTransactionManager as follows.

    HibernateTransactionManager manager = new HibernateTransactionManager(sessionFactory);
    manager.setNestedTransactionAllowed(true);
    return manager;

Please refer to https://www.demo2s.com/java/spring-hibernatetransactionmanager-setnestedtransactionallowed-boolean.html

Jalandar R
  • 11
  • 3