Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Hibernate interceptor and event listeners

I wonder if it's possible to find out what hibernate really did to the database (i.e., committed changes). I'd like to notify another process on certain changes.

I guess that the EventTypes POST_COMMIT_DELETE, POST_COMMIT_UPDATE and POST_COMMIT_INSERT should do, but given exactly zero documentation, it's only a guess. Can someone confirm? Am I missing any?

I'm also unsure about how to obtain what gets really written. The PostInsertEvent contains both Object entity and Object[] state, which of the two should I trust?


A side question: I'm using no XML, no Spring, no JPA, just Configuration and buildSessionFactory. Is this really the way listeners should be registered?

 EventListenerRegistry registry = ((SessionFactoryImpl) sessionFactory)
    .getServiceRegistry()
    .getService(EventListenerRegistry.class);
registry.appendListeners(....);

I'm asking as its 1. dependent on an implementation detail, 2 totally ugly, 3. nearly perfectly undiscoverable.

like image 976
maaartinus Avatar asked Sep 14 '16 23:09

maaartinus


People also ask

What is interceptor in hibernate?

The Hibernate Interceptor is an interface that allows us to react to certain events within Hibernate. These interceptors are registered as callbacks and provide communication links between Hibernate's session and application.

How do I register the Hibernate Interceptor?

A Hibernate interceptor can either be registered as Session-scoped or SessionFactory-scoped. In the above, we explicitly registered an interceptor with a particular hibernate session. 3.2: SessionFactory-scoped Interceptor: A SessionFactory-scoped interceptor is registered before building a SessionFactory.


1 Answers

Yes, it is possible to notify another process(For Example: Auditing) after committing certain changes in the DB. That is to do certain things right after the JDBC transaction(Hibernate wraps JDBC transaction ) is committed using Custom Interceptors and Events of Hibernate.

You can create your own custom interceptor class by extending it by EmptyInterceptor class of hibernate. And by overriding the below afterTransactionCompletion(Transaction tx) method of EmptyInterceptor to do certain tasks after the transaction has been committed.

public class AuditLogInterceptor extends EmptyInterceptor {
 @Override
 public void afterTransactionCompletion(Transaction tx) {
    System.out.println("Task to do after transaction ");
 }
}

The Event system can be used in addition, or as a replacement, for interceptors.

Below listed are few ways to perform certain task after transaction event is completed/committed

1.Implement AfterTransactionCompletionProcess interface from org.hibernate.action package and implement the below method. documentation

void doAfterTransactionCompletion(boolean success, SessionImplementor session) {
      //Perform whatever processing is encapsulated here after completion of the transaction.
}      

Otherwise, you can extend your CustomDeleteAction class with EntityDeleteAction and override the above doAfterTransactionCompletion method. documentation

2.By Implementing PostDeleteEventListener and using EventType.POST_COMMIT_DELETEfor post delete.
By Implementing PostInsertEventListener and using EventType.POST_COMMIT_INSERTfor post insert.
By Implementing PostUpdateEventListener and using EventType.POST_COMMIT_UPDATEfor post update.
Here are few examples of PostDeleteEventListener , PostUpdateEventListener and PostInsertEventListener.


The Object entity of PostInsertEvent gives the entity involved in the database operation.

The Object[] state of PostInsertEvent returns the session event source for this event. This is the underlying session from which this event was generated.
Below link contains the documentation for PostInsertEvent Members.

http://mausch.github.io/nhibernate-3.2.0GA/html/6deb23c7-79ef-9599-6cfd-6f45572f6894.htm


Registering event listeners: Below MyIntegrator class shows 3 ways to register event listeners.

public class MyIntegrator implements org.hibernate.integrator.spi.Integrator {

public void integrate(Configuration configuration, SessionFactoryImplementor sessionFactory, SessionFactoryServiceRegistry serviceRegistry) {
    // As you might expect, an EventListenerRegistry is the thing with which event listeners are registered  
    // It is a service so we look it up using the service registry
    final EventListenerRegistry eventListenerRegistry = serviceRegistry.getService( EventListenerRegistry.class );

    // If you wish to have custom determination and handling of "duplicate" listeners, you would have to add an
    // implementation of the org.hibernate.event.service.spi.DuplicationStrategy contract like this
    eventListenerRegistry.addDuplicationStrategy( myDuplicationStrategy );

    // EventListenerRegistry defines 3 ways to register listeners:
    //     1) This form overrides any existing registrations with
    eventListenerRegistry.setListeners( EventType.AUTO_FLUSH, myCompleteSetOfListeners );
    //     2) This form adds the specified listener(s) to the beginning of the listener chain
    eventListenerRegistry.prependListeners( EventType.AUTO_FLUSH, myListenersToBeCalledFirst );
    //     3) This form adds the specified listener(s) to the end of the listener chain
    eventListenerRegistry.appendListeners( EventType.AUTO_FLUSH, myListenersToBeCalledLast );
}
}

Hence, Listeners registration to a event is dependent on implementation detail.

like image 142
Rohit Gaikwad Avatar answered Oct 08 '22 07:10

Rohit Gaikwad