Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

like image 676
redbull Avatar asked Feb 04 '11 08:02

redbull


People also ask

What is the correct sequence of JPA life cycle?

JPA's 4 Lifecycle States. The lifecycle model consists of the 4 states transient, managed, removed, and detached.

What is @PrePersist in JPA?

JPA specifies seven optional lifecycle events that are called: before persist is called for a new entity – @PrePersist. after persist is called for a new entity – @PostPersist. before an entity is removed – @PreRemove. after an entity has been deleted – @PostRemove.

How does @PrePersist work?

The @PrePersist annotation is used to configure a callback for pre-persist(pre-insert) events of the entity. In other words, it is used to annotate model methods to indicate that the method should be called before the entity is inserted (persisted) into the database.

What is JPA callback?

JPA includes a variety of callbacks methods for monitoring changes in the lifecycle of your persistent objects. These callbacks can be defined on the persistent classes themselves and on non-persistent listener classes.


2 Answers

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.

like image 73
Stefan Haberl Avatar answered Sep 24 '22 17:09

Stefan Haberl


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.

like image 45
Erik Avatar answered Sep 26 '22 17:09

Erik