Liang Zhou
Liang Zhou

Reputation: 2165

How to declare `@Transactional` in a Spring Boot service so exception is thrown "immediately"?

Say I have the following spring beans in a spring boot app. My intent is to make createFoo() transactional so:

  1. When barService.bar() throws exceptions, the persist gets rolled back.
  2. When the persist throws exception, the exception propagates up to the caller "immediately" so barService.bar() is NOT called.
@Service
public class FooService
{
    @Autowired
    private FooRepository fooRepository;
    @Autowired
    private BarService barService;

    @Transactional
    public void createFoo(Foo foo) {
        fooRepository.save(foo);
        // expect to not execute when the above line throws exceptions
        barService.bar();
    }
}

@Service
public class BarService {
    public void bar() {

    }
}

So far the 1st requirement works, however the 2nd doesn't. When the persist throws exception, barService.bar() is AlWAYS called.

If I remove @Transactional, 2nd requirement works, the 1st doesn't.

I also tried all Propagation types, none of them work as I expected. For example, if I use @Transactional(MANDATORY), I get the following error:

org.springframework.transaction.IllegalTransactionStateException: No existing transaction found for transaction marked with propagation 'mandatory'

Upvotes: 1

Views: 611

Answers (1)

Mr.J4mes
Mr.J4mes

Reputation: 9266

Without @Transactional, each call to a repo method is a standalone transaction and it will be flushed immediately. That's why your 2nd requirement worked without @Transactional.

When you add @Transactional, the whole createFoo() becomes one single unit of transaction. Hence, the changes you make when calling save() will only be flushed when createFoo() completes its execution. That's why your 1st requirement worked with @Transactional.

To achieve what you want, keep @Transactional and call saveAndFlush() instead of save().

Upvotes: 3

Related Questions