I got a Problem with my HibernateInterceptor. I extend the EmptyInterceptor
and override the onFlushDirty
Method.
I use this method to manually check dirty values (compare previous values to current values) to write audit-logs for changed entities.
The problem is, that in some specific situations it happens, that the same entity is passed to the onFlushDirty
method several times before the postFlush
method is called. The previous values and current values do not change from call to call. So my audit-log writes several times the same changes.
If a property of my entity changes (e.g. from NEW
to IN_PROGRESS
) this change is passed two or more times to the onFlushDirty
.
Why is this happening? This is real odd behavior and not expected in my opinion.
The call of the interceptor onFlushDirty
is caused by the auto-flush
behavior of Hibernate. When a query is executed during a session it flushes all dirty entities in the session. I expect this to be done just once for a dirty entity, but it seems that the entity is still marked as "dirty" even after the flush. Then another query is executed within the session and again - the entity is flushed again. Old values and current values are the same as at the first flush.
I tried to reproduce this problem with a test-case but i could not manage to provoke such multiple flushes. I hope you Hibernate experts can help me out of this, before i have to debug the whole Hibernate code.
Cheers, Chris
After some debugging, i found the reason for the multiple calls of onFlushDirty
:
As explained above, the flushmode in my application is set to AUTO. Before a query is executed within a transaction, Hibernate decides whether to flush dirty entities or not. Whatever the outcome of this decision is: the method onFlushDirty
in the HibernateInterceptor
is called for sure for every dirty entity in the session even if it is decided not to be flushed afterwards.
If an entity of type A is in dirty state in the session and a query for entity type B is executed within this session, Hibernate does not flush the dirty entity because it does not affect the table the query is using and so the flush is not needed.
If there are multiple queries executed within a session it can occur that the onFlushDirty method is called several times for the same dirty entity but it gets never really flushed to the database and remains dirty until the running transaction is committed.
Have a look at the Hibernate class DefaultAutoFlushEventListener
public void onAutoFlush(AutoFlushEvent event) throws HibernateException {
...
if ( flushIsReallyNeeded(event, source) ) {
log.trace("Need to execute flush");
...
}
else {
log.trace("Dont need to execute flush");
...
}
}
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