I implemented a Hibernate Event Listener like so:
public class AuditListener implements PostInsertEventListener {
private static final long serialVersionUID = -966368101369878522L;
@Override
public void onPostInsert(PostInsertEvent event) {
if (event.getEntity() instanceof Auditable) {
StatelessSession session = null;
try {
session = event.getPersister().getFactory().openStatelessSession();
Auditable auditableEntity = (Auditable)event.getEntity();
session.beginTransaction();
session.insert(new AuditTrail(auditableEntity.getClass().getSimpleName(),
auditableEntity.getId(), auditableEntity.getStatus(),
auditableEntity.getLastModified()));
session.getTransaction().commit();
} catch (HibernateException he) {
System.out.println("Horrible error: " + he.getMessage());
session.getTransaction().rollback();
} finally {
if (session != null) {
session.close();
}
}
}
}
}
All it does is insert an AuditTrail
object into the database right after inserting any Auditable
object.
The problem I am having comes when there is any sort of exceptional situation during the transaction that persists the Auditable
object: the transaction is rolled back, but I still get an AuditTrail
record inserted.
I tried to turn this:
StatelessSession session = event.getPersister().getFactory().openStatelessSession();
Into this:
Session session = event.getSession();
But when I attempt to use that session it results in a stack trace that ends in the message Session is closed
.
The problem seems to be that the event fires in the middle of the transaction, before the exceptional situation that results in the rollback, and since the Event Listener has to use its own session, it doesn't also get rolled back.
Is there some way to make sure the action of the Event Listener is also rolled back? Have I just chosen an event that occurs too early in the transaction? Is there some event I should be catching that happens after the last point at which a rollback could happen, thus ensuring that the insertion of the AuditTrail
will not trigger if a rollback occurs?
Since nobody ever replied, I kept researching on my own, and my initial solution is as follows:
public class AuditListener implements PostInsertEventListener {
private static final long serialVersionUID = -966368101369878522L;
@Override
public void onPostInsert(PostInsertEvent event) {
if (event.getEntity() instanceof Auditable) {
Session session = null;
try {
session = event.getPersister().getFactory().getCurrentSession();
Auditable auditableEntity = (Auditable)event.getEntity();
session.save(new AuditTrail(auditableEntity.getClass().getSimpleName(),
auditableEntity.getId(), auditableEntity.getStatus(),
auditableEntity.getLastModified()));
} catch (HibernateException he) {
System.out.println("Horrible error: " + he.getMessage());
session.getTransaction().rollback();
}
}
}
}
Note that I'm calling "getCurrentSession()
" from the PostInsertEvent
's SessionFactoryImplementor
. I'm not really sure if this is a potentially dangerous strategy or not, and I'm also not sure if it makes sense to keep that rollback()
call in there, but it seems to function and no one else ever supplied a better solution. So there you go.
I had a very similar problem recently. The questions was asked years ago but I think this answer might help others.
The problem I am having comes when there is any sort of exceptional situation during the transaction that persists the Auditable object: the transaction is rolled back, but I still get an AuditTrail record inserted.
The real problem seems to me, is that onPostInsert
shouldn't even get fired when the transaction is NOT committed.
It turned out to be a bug of PostInsertEventListener
in hibernate (for 8 years! from 2006 to 2014). Ref: https://hibernate.atlassian.net/browse/HHH-1582
For backward compatibility, they fixed the issue by introducing a new PostCommitInsertEventListener
. So we should use PostCommitInsertEventListener
instead now (for hibernate >= v4.3.5) and onPostInsert
should get fired only when transaction is successfully committed
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With