Spring boot transaction keeps running after commiting in async method

Viewed 295

I have this scenario:

@Transactional
public void setStopped(Machine machine)
{
    machine.setStatus(StatusType.STOPPED);
    machineRepository.saveAndFlush(machine);
}

@Transactional
public void setRunningAndAvailable(Machine machine)
{
    machine.setStatus(StatusType.RUNNING);
    machine.setAvailable(true);
    machineRepository.saveAndFlush(machine);
}

@Async
public void restart(Machine machine, int bound, int sec)
{
    try
    {
        if(machine.getStatus().equals(StatusType.RUNNING))
        {
            Random random = new Random();
            int number = random.nextInt(bound) * 1000;
            Thread.sleep((sec * 1000L) + number);

            setStopped(machine);

            number = random.nextInt(bound) * 1000;
            Thread.sleep((sec * 1000L) + number);

            setRunningAndAvailable(machine);
        }
    }
    catch(Exception e)
    {
        e.printStackTrace();
    }
}

I keep getting the following errors:

org.springframework.orm.ObjectOptimisticLockingFailureException

Caused by: 
org.hibernate.StaleObjectStateException: Row was updated or deleted by another 
transaction (or unsaved-value mapping was incorrect)

The DB doesn't update after the first method ends (setStopped) and I get these errors when I try to saveAndFlush for the second time in (setRunningAndAvailable) which leads me to believe that somehow the first transaction is still ongoing.

I tried to do @Transactional(propagation = Propagation.NESTED) and @Transactional(propagation = Propagation.REQUIRES_NEW) but I got the same errors.

I don't know why this keeps happening, if anyone could help me I would appreciate it a lot.

1 Answers

You need to know that @Transactional works with AOP, so the behaviour (the creation and commit of the transaction) is added before entering your method and right after the return.

The main problem is that your are calling methods from the same bean, so you are not traversing the proxy layer of the bean, and not triggering the @Transactional behaviour..

You need to move the annotated methods in another class, and inject that bean in your class.

Related