0

I've read the directives in the Spring @Transactional - isolation, propagation

but I don't understand how made this feature that I explain: I've an asynchronus method like this

@Transactional(timeout = TRANSACTION_TIMEOUT, propagation = Propagation.REQUIRES_NEW)
@Async("asyncImportExecutor")
public void startBeggin(Long id, String jwtToken) {

    try {
        . . .

    } catch (Exception e) {
        log.error("Error: " + e);

        utilsService.setFlag(id, 0L); // every type of error, revert flag to 0
    }

and the utilService method called on catch, is this

 public void setFlag(Long id, Long state) {

    /* recover data from repository */
    Processo processo = getRepo().getOne(id);
    processo.setAvanzamento(state);
    getRepo().saveAndFlush(processo);
}

this method (setFlag) is called one time passing 1L before call the asynchronus method

getService().setFlag(id, (long) 1);

and at the end of all operations in asynchronus method passing zero

getService().setFlag(id, (long) 0);

but, if the asynchronus method fail for some problems, the call in the catch branch fail, because

org.springframework.orm.jpa.JpaSystemException: Transaction was marked for rollback only; cannot commit; nested exception is org.hibernate.TransactionException: Transaction was marked for rollback only; cannot commit

and the flag remain to 1.

So, I hope I was clear, but ... how can I make sure that, on any exception that occurs between the operations within the asynchronous method (startBeggin) after the rollback of that operations, set that value on that object?

How can I set (or update) a field on an object, on the roolback of a transaction (failed)?

The object impacted of the transactional method is the same (recovered by ID) but all the roolbacked operations don't are linked to that flag, that I want to set anyhow.

Thanks in advance to anyone who can give me a solution / idea.

Domenico
  • 292
  • 2
  • 10
  • 26

1 Answers1

1

The approach depends very much on what you want to accomplish here. But trying to give a simple answer:

Transaction was marked for rollback only

means that all changes made database resources will be rolled back(not persisted) at the end of the transaction -> in your case at the end of your startBeggin method.

Thus, any database resources changed in utilsService.setFlag will also not be persisted -> beacasue the current transaction is already marked for rollback.


To avoid that, you need to have a new transaction @Transactional(propagation = Propagation.REQUIRES_NEW) on utilsService.setFlag which will be isolated from the transaction created in startBeggin method.

You also should remember when @Transactional works:

https://docs.spring.io/spring/docs/4.2.x/spring-framework-reference/html/transaction.html#transaction-declarative-annotations

Andrew K.
  • 56
  • 1
  • 8