0

I have a Spring Boot application with persistence using Hibernate/JPA.

I am using transactions to manage my database persistence, and I am using the @Transactional annotation to define the methods that should execute transactionally.

I have three main levels of transaction granularity when persisting:

  1. Batches of entities to be persisted
  2. Single entities to be persisted
  3. Single database operations that persist an entity

Therefore, you can imagine that I have three levels of nested transactions when thinking about the whole persistence flux.

The interaction between between levels 2 and 3 works transparently as I desire because without specifying any Propagation behaviour for the transaction, the default is the REQUIRED behaviour, and so the entire entity (level 2) is rolled back because level 3 will support the transaction defined in level 2.

However, the problem is that I need an interaction between 1 and 2 that is slightly different. I need an entity to be rolled back individually if an error were to occur, but I wouldn't like the entire batch to be rolled back. That being said, I need to specify a propagation behavior in the level 2 annotation @Transactional(propagation = X) that follows these requirements.

I've tried REQUIRES_NEW but that doesn't work because it commits some of the entities from level 2 even if the whole batch had to be rolled back, which can also happen.

The behaviour that seems to fit the description better is NESTED, but that is not accepted when using Spring and Hibernate JPA, see here for more information.

This last link offers alternatives for the NESTED type, but I would like to know if NESTED would've really solved my problem, or if there was another behaviour that suited the job better.

Matt
  • 144
  • 15

1 Answers1

1

I guess NESTED would roughly do what you want but I would question if this really is necessary. I don't know what you are trying to do or what the error condition is, but maybe you can get rid of the error condition by using some kind of WHERE clause or an UPSERT statement: Hibernate Transactions and Concurrency Using attachDirty (saveOrUpdate)

Christian Beikov
  • 15,141
  • 2
  • 32
  • 58
  • Actually I don't want to get rid of the error condition. You see, the errors on level 2 are well known "business" errors, so I do want to catch them and rollback a single entity. On the other hand, errors on level 1 are unexpected, so I would like to log them and rollback the whole batch. It would be nice to have two "levels of rollback granularity", but I think the only propagation behaviour that does it is NESTED, but that my JPA does not support, so I have to settle for just one level of rollback adjustment. I was wondering if there is a workaround that still uses Spring's Transactions. – Matt Sep 30 '21 at 13:41
  • None that I know of. The question is, whether these errors have to be database errors i.e. data validation can to some extent occur without causing exceptions on the JDBC level, since a JDBC exception requires a TX rollback. – Christian Beikov Sep 30 '21 at 16:28
  • 1
    And by the way, here a nice article about possible issues with save points which might help you reconsider your approach: https://postgres.ai/blog/20210831-postgresql-subtransactions-considered-harmful – Christian Beikov Oct 01 '21 at 10:04