In new Hibernate Session created in event can't see entity saved in different session (but same transaction)
I am using Hibernate's PreInsertEventListener
to do auditing of fields of my table.
I am also using Spring to create my SessionFactory and TransactionManager.
Some other detail that might be relevant:
OpenSessionInViewFilter is used Hibernate version: 3.5.1-Final Spring version: 3.0.3.RELEASE Oracle 10g databaseIt is unsafe to use the Session in event because it is probably being flushed, thus I create a new Session.
public boolean onPreInsert(final PreInsertEvent event) {
final SessionFactory factory = triggeringSession.getSessionFactory();
Session triggeringSession = event.getSession();
triggeringSession.doWork(new Work() {
public void execute(Connection connection) throws SQLException {
Session newSession = factory.openSession(connection);
saveStuff(newSession);
newSession.flush();
}
});
return false;
}
In my saveStuff
method I need save a new entity.
private void saveStuff(Session session) {
HistoricReference historicReference = new HistoricReference();
historicReference.setId("12345"); // This is actually an unique ID based on a generated auditing number and table that was inserted into
// If this haven't been created I want it to be saved
if (session.get(HistoricReference.class, "12345") == null) {
session.save(historicReference);
}
// Other stuff saved (regarding old/new values etc.) that historicReference as id (as part of composite id)
}
My problem is that if I insert 2 new entities of the same type in the same transaction I get a unique constraint violation on the HistoricReference table. I debugged and the code that checks if it is already created always returns false, but in the end when the transaction gets commited it tries to insert it twice. Is this because a new session is created each time?
Example:
MyEntity entity1 = new MyEntity();
MyEntity entity2 = new MyEntity();
session.save(entity1);
session.save(entity2);
I will get a unique constraint error at the end of the request (when trying to commit). This is because when onPreInsert(...)
is called for entity2 it will call session.save(historicReference)
again. If I don't save entity2 no problem is encountered.
Will session.get(HistoricReference.class, "12345")
return a value even if it was saved in a different Session but the same uncommitted transaction?
I have a workaround for the problem but it is a bit hacky (a boolean value binded to transaction using TransactionSynchronizationManage开发者_运维技巧r
to prevent historicReference from being saved twice) and would prefer a cleaner solution (or at least better understanding why it is not working as I expect it to).
Any help will be appreciated.
Please use session.merge()
instead of session.save()
. And here is an excellent explaination why.
Hope that helps.
One solution is to move the saving of the HistoricReference to the FlushEvent. In preInsert event just get the data and collect it in a thread local map / list and then access and save them in the FlushEvent.
精彩评论