user2046810
user2046810

Reputation: 393

jpa @postpersist @postupdate only after transaction commit

I'm inserting/updating 3 tables while using manual transaction. I want to insert into an history table right after the transaction was committed. that means that there were 3 em.persist actions (for each table), and only after committing them I would like to call a method.

This is my code:

@Resource
private EJBContext context;

public void save(Object obj)
{
    try 
    {     
        transaction = context.getUserTransaction();
        transaction.begin();

        em.persist(obj);

        sb2.save(obj);  //persist in  sb2                         
        sb3.save(obj);  //persist in  sb2                         

        transaction.commit(); 
    }
    catch (Exception exp) 
    {
       transaction.rollback();        
    }   
 }

Is there any kind of post commit method? How can I call a method after the commit, and not after the persist?

Upvotes: 7

Views: 6740

Answers (3)

Xavier Dury
Xavier Dury

Reputation: 1571

If you are in a JPA 2.2 + CDI + JTA environment, you could leverage CDI events which can be observed at a specified transaction phase.

@Retention(RetentionPolicy.RUNTIME)
@Qualifier
public @interface EntityEvent {}

public class MyListener {

    @Inject
    @EntityEvent
    private Event<Object> event;

    @PostUpdate
    public void postUpdate(Object entity) {
        event.fire(entity);
    }
}

public class MyObserver {

    public void afterCommit(@Observes(during = TransactionPhase.AFTER_SUCCESS) @EntityEvent Object entity) {
        // do something...
    }
}

@EntityListeners(MyListener.class)
public class MyEntity {}

Upvotes: 2

Xavier Dury
Xavier Dury

Reputation: 1571

You could use TransactionSynchronizationRegistry to register a callback to be executed after the transaction completes:

public class MyListener {

    // if you can't inject it with @Resource, you'll have to fetch it from JNDI
    @Resource
    private javax.transaction.TransactionSynchronizationRegistry registry;

    @PostUpdate
    public void postUpdate(final Object entity) {
        registry.registerInterposedSynchronization(new Synchronization() {

            public void beforeCompletion() {}

            public void afterCompletion(int status) {
                if (status == javax.transaction.Status.STATUS_COMMITTED) {
                    // Do something with your entity
                }
            }
        });
    }
}

Then annotate your entities with @EntityListeners(MyListener.class) (or add it in your orm.xml).

Upvotes: 6

James
James

Reputation: 18379

JPA does not provide such events, but EclipseLink provides extended events through the SessionEventListener API.

http://eclipse.org/eclipselink/documentation/2.5/jpa/extensions/p_session_event_listener.htm

You could also consider the container JTA events.

Upvotes: 0

Related Questions