Common Transaction Propagation Pitfalls in Spring Framework

safa ertekin
3 min readJul 21, 2017

--

In my first post i would like to give you a summary of common propagation mistakes that Spring developers made while using transactional features of Spring framework. Before diving into details let’s first remember how propagation works in Spring. Let’s look at Ken Tousen’s notes on propagation annotations which will help us remember each of them clearly.

  1. Private methods

When you call a private method that has REQUIRES_NEW annotation from a public method no new transaction will be created.

@Transactional
public class MusicPlayerService {

@Autowired
Song song;

@Autowired
MusicCatalogueService musicCatalogueService;

public void playSong() {
scrobble();
song.play();
}

@Transactional(propagation = Propagation.REQUIRES_NEW)
private void scrobble() {
musicCatalogueService.scrobble(song);
}
}

In the example above we will not able to play song if the music catalogue service fails to scrobble because they will all execute in a single transaction.

So make your method public if it requires a new transaction

2. Method calls within same class

If your method requires a new transaction to be executed it must be in a separate class/service. Otherwise it gets executed within same transaction.

Seperation of classes could be done like the example below:

@Transactional
public class MusicPlayerService {

@Autowired
Song song;

@Autowired
MusicCatalogueService musicCatalogueService;

public void playSong() {
musicCatalogueService.scrobble(song);
song.play();
}
}
public class MusicCatalogueService {

@Autowired
ScrobbleRepository scrobbleRepository;

@Transactional(propagation = Propagation.REQUIRES_NEW)
public void scrobble(Song song) {
scrobbleRepository.save(song);
}
}

3. SUPPORTS propagation combined with readonly flag

If there is no ongoing transaction then SUPPORTS will not create a new transaction. Then read only flag will be ignored.

4. CRD operations combined readonly flag

If we use any of REQUIRED or REQUIRES_NEW propagation combined with readonly flag and attempt to do one of the CREATE,DELETE or UPDATE operations then we will end up getting read only connection exception.

5. Checked Exceptions

If we get RuntimeException our transactions will rollback. That’s quite reasonable. What if our program throws checked exceptions?

The answer is transaction will not be rolled back. So how are we going to handle these cases?

Spring has transactional setting named rollbackFor. By mentioning exception types that must trigger rollback action you make sure that your transaction roll backs in checked exception situation. The usage of this is as folllows:

@Transactional(rollbackFor = Exception.class)
public void rollBackActionDefinedMethod() {
}

That’s the end of my post.

Please don’t hesitate to send me your feedbacks about this post. Contributions on this topic is also appreciated.

The references:

--

--