Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring nested transactions

In my Spring Boot project I have implemented following service method:

@Transactional public boolean validateBoard(Board board) {     boolean result = false;     if (inProgress(board)) {         if (!canPlayWithCurrentBoard(board)) {             update(board, new Date(), Board.AFK);             throw new InvalidStateException(ErrorMessage.BOARD_TIMEOUT_REACHED);         }         if (!canSelectCards(board)) {             update(board, new Date(), Board.COMPLETED);             throw new InvalidStateException(ErrorMessage.ALL_BOARD_CARDS_ALREADY_SELECTED);         }         result = true;     }     return result; } 

Inside this method I use another service method which is called update:

@Transactional(propagation = Propagation.REQUIRES_NEW) public Board update(Board board, Date finishedDate, Integer status) {     board.setStatus(status);     board.setFinishedDate(finishedDate);      return boardRepository.save(board); } 

I need to commit changes to database in update method independently of the owner transaction which is started in validateBoard method. Right now any changes is rolling back in case of any exception.

Even with @Transactional(propagation = Propagation.REQUIRES_NEW) it doesn't work.

How to correctly do this with Spring and allow nested transactions ?

like image 462
alexanoid Avatar asked May 13 '16 18:05

alexanoid


People also ask

Does Spring support nested transactions?

Not all transaction managers support nested transactions. Spring supports this out of the box only with the JDBC DataSourceTransactionManager, which is what we'll cover.

Can transactions be nested?

A nested transaction is used to provide a transactional guarantee for a subset of operations performed within the scope of a larger transaction. Doing this allows you to commit and abort the subset of operations independently of the larger transaction.

How does @transactional work in Spring?

So when you annotate a method with @Transactional , Spring dynamically creates a proxy that implements the same interface(s) as the class you're annotating. And when clients make calls into your object, the calls are intercepted and the behaviors injected via the proxy mechanism.


1 Answers

This documentation covers your problem - https://docs.spring.io/spring-framework/docs/current/spring-framework-reference/data-access.html#transaction-declarative-annotations

In proxy mode (which is the default), only external method calls coming in through the proxy are intercepted. This means that self-invocation, in effect, a method within the target object calling another method of the target object, will not lead to an actual transaction at runtime even if the invoked method is marked with @Transactional. Also, the proxy must be fully initialized to provide the expected behaviour so you should not rely on this feature in your initialization code, i.e. @PostConstruct.

However, there is an option to switch to AspectJ mode

like image 156
Jakub Bibro Avatar answered Sep 20 '22 04:09

Jakub Bibro