Events after Transaction Commit Spring JPA

10,847

Assuming, as your comment mentions, that you are using an entity manager to persist/merge your entity object, you probably have a Bean that wires it in. If so, then in order to take advantage @TransactionalEventListener, you want to wire in ApplicationEventPublisher bean. You class might look like:

@Component
public class OrderManager {
    @PersistenceContext
    protected EntityManager entityManager;

    // You need this Spring bean
    @Autowired
    private ApplicationEventPublisher applicationEventPublisher;

    // ...
    @Transactional
    public void saveOrder(Order newOrder) {
        entityManager.persist(newOrder);
        applicationEventPublisher.publishEvent(new OrderEvent());
    }

    @TransactionalEventListener
    public void doAfterCommit(OrderEvent event){
        //process here
    }

    // inner class for brevity, you may not want to do this in practice
    public static class OrderEvent {
    }   
}

This code (although horribly put together in a single class..) is just to illustrate this point: if you want @TransactionalEventListener to trigger, then you need to (at least):

  1. Define it in a Spring managed bean
  2. Wire in an "ApplicationEventPublisher" somewhere where your @Transactional lives (doesn't have to be the same bean at Step 1)
  3. Call "applicationEventPublisher.publishEvent()" inside @Transactional method

The default behaviour will trigger the TransactionalEventListener after the commit is complete & entity manager is flushed, but still within the bounds of the transaction. You can change this within the annotation with the 'phase' param, but this should be enough to address your issue.

ps. you can glean most of this from https://spring.io/blog/2015/02/11/better-application-events-in-spring-framework-4-2 as JB Nizet says

Share:
10,847
Ysak
Author by

Ysak

I am a software engineer, passionate in learning and using the new technologies in building better software. Working experience in Elastic, RabbitMq, Amazon Services along with Java And Javascript as the core language that I have chosen.

Updated on June 09, 2022

Comments

  • Ysak
    Ysak almost 2 years

    I need to do some specific action after the successful transaction commit, which basically includes my analytical operations about the data;

    I tried using the following code snippet

    public class EntityEventHandlers {
        private static Logger logger = LoggerFactory.getLogger(EntityEventHandlers.class);
    
        @Autowired
        private AsyncEventBus async;
    
        @PostUpdate
        public void postUpdate(Order order) {
            AutowireHelper.autowire(this, this.async);
            logger.debug("post update called " + order.getId());
            async.post(new ESCreateOrderEvent(order));
        }
    
        @PostPersist
        public void postPersist(Order order) {
            AutowireHelper.autowire(this, this.async);
            logger.debug("post insert called " + order.getId());
            async.post(new ESCreateOrderEvent(order));
        }
    }
    

    But found that by when my the order is not persisted.

    Can somebody tell me a better solution where I can trigger some action after transaction commit is successful.

    I heard(tried using) about @TransactionEventListener, but didnt see anything triggering.

    Updated the source

    @Component
    public class TXEventHandler {
        @TransactionalEventListener
        public void doAfterCommit(ApplicationEvent event){
            //process here
        }
    }
    

    About the application Its a Spring MVC based on 4.2.0 and uses Hibernate and MySql as the db.

    Right now I have solved the problem by putting the event into a delay queue and the delay is sufficient to happen the db commit. But I know its not a good solution. So let me know if someone have faced this issue and able to fix it.

    Thanks In Advance.