scrim
scrim

Reputation: 63

How to perform another DB query in the same transaction in case of unique constraint violation in Java Spring @Transactional method?

I am struggling with handling exceptions during transactional methods with Spring @Transactional annotations. Currently, when my Dao insert method throws a unique contraint violation, I want to perform a read instead to get the existing item. However, this fails because the UniqueIdViolation causes the transaction to fail. How can I refactor this to work as intended whilst not doing a dodgy boolean return on the insert?

I have a DAO with an insert method, e.g.:

public class ItemDao {
  
  public void insertItem(Item item) {
    // insert into db via jooq
  }

  public Item fetch(String id) {
    // fetch from db
  }
  ...
}

If it violates a unique constraint I have an aspect that handles the DataAccessException and rethrows it as a UniqueIdException.

I have a service method that takes in some information and creates an Item, before returning that item.

If the dao throws a UniqueIdException, I want the service to catch this error and then call itemDao.find() to get the existing Item and return it.

public class MyServiceImpl implements MyService {
  
  @Transactional(isolation = SERIALIZABLE)
  public Item createItem(...) {
    Item item = new Item(...);
    try {
      itemDao.insert(item);
      return item;
    } catch (UniqueIdException ex) {
      return itemDao.find(item.getId());
    }
  }
}

The issue here is when itemDao.insert(item) throws an exception this causes the transaction to fail and therefore itemDao.find() doesn't run.

Upvotes: 0

Views: 88

Answers (1)

Minnow
Minnow

Reputation: 515

@Transactional is setup to rollback, by default, only when an unchecked exception is thrown.

Since DataAccessException is unchecked exception your transaction will be rolled backed.

A better strategy will be to first call fetch() if returned null then call insertItem

Upvotes: 0

Related Questions