redbull
redbull

Reputation: 745

JPA / @PostPersist @PostUpdate - transaction

I am currently working with @PostPersist and @PostUpdate, and in those triggers I am persisting additional entities. The question is, are those triggers in the same transaction and if not is it possible to force it ?

For me it works this way. While I was looking through the logs the transaction isn't existing ( it's commited just before the trigger is launched ) which prevents me ( without REQUIRES_NEW on the persisting method from injected bean ) from saving the additional entities in database. REQUIRED attribute is totally ignored, and MANDATORY attribute do not throw an exception.

Can it be the problem with JUnit ( since I am in the dev. phase and did not test the behavior on full env. ) ?

If extending the transaction on this triggers is not possible, how to ensure that if the rollback occurs before the @PostPersist and @PostUpdate, those operations also will be rollbacked.

Upvotes: 21

Views: 31476

Answers (2)

Stefan Haberl
Stefan Haberl

Reputation: 10549

If you're using Spring you could always register a TransactionSynchronization with your current transaction manager to be called back on events such as commits of your currently running transaction:

@PostPersist
void onPersist() {
    TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() {

      @Override
      public void beforeCommit(boolean readOnly) {
        // do work
      }
    });
  }    
}

A TransactionSynchronization also provides callbacks after a transaction has committed successfully and before/after a transaction completes.

If you need to inspect if the transaction was committed or rolled back, use afterCompletion(int status).

For details have a look at TransactionSynchronization's JavaDoc.

Upvotes: 29

Erik
Erik

Reputation: 2051

The firing of a PostPersist event does not indicate that the entity has done a successful commit. The transaction may be rolled back after the firing of the event but before the successful commit. If you in the PostPersist get the entity manager used in the transaction and then do somehting like this:

@PostPersist
void someMethod() {
  EntityManager em = null;
  em = getEntityManagerUsedInTransaction();
  EntityTransaction et = em.getTransaction(); // should return the current transaction
  if (et.isActive() ) {
    // do more db stuff
  }
}

NB: I haven't tried this so it's only speculation (tho' I have used the lifetime event trigger extensively for other stuff). I have to add that I don't think this is a good idea. Use the PostPersist to flag that other entities should be persisted and do it in another transaction.

Upvotes: 13

Related Questions