New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Session not flushed with Hibernate 4.1.3, JTA and Spring transaction management integration [SPR-9404] #14040

Closed
spring-issuemaster opened this Issue May 13, 2012 · 5 comments

Comments

Projects
None yet
2 participants
@spring-issuemaster
Copy link
Collaborator

spring-issuemaster commented May 13, 2012

Koen Serneels opened SPR-9404 and commented

I have been migrating from hibernate 3.3.x to hibernate 4.1.3-final using Spring 3.1.1-release.
Besides the hibernate specific refactorings (due to API changes) I thought the only changes for the Spring integration were changing packages names:

  • Use the LocalSessionFactoryBean from the hibernate4 package
  • Use the HibernateTransactionManger (which we only use for testing) from the hibernate4 package.

As it turned out the migration when smooth and everything was working on a local tomcat.
However, once we ran our app on glassfish with the JtaTransactionManager (I tested it on GF3.1.2) we got a "No Session found for current thread" when obtaining sessionFactory.currentSession().
After checking SpringSessionContext, we learned that if TransactionSynchronizationManager does not return a existing session or SessionHolder, a check
is performed for a jtaSessionContext, which was null.
The fact that no SessionHolder is registered made also sense as this done by the HibernateTransactionManager and we are using the JtaTransactionManager.

So then learned that in case of JTA you have to specify manually how the tx manager/user transaction can be found.
This was done automatically for you in the hibernate3 LocalSessionFactoryBean, but no longer in the hibernate4 LocalSessionFactoryBean.
So to solve this we configured:

hibernate.transaction.jta.platform and set it to SunOneJtaPlatform.

This resolved the "No Session found for current thread" as it initialized the jtaSessionContext with the txmanager provided by the configured JtaPlatform.

However, now it turns out that the hibernate session is not flushed before the transaction is commited and hence no modifications are written to database.
In the supplied sample we have a basic hibernate setup with H2. Next we have a JtaTransactionManager and a transactional facade.
Next we have a test entity having a single property. The facade has two methods, one to store the entity and one to retrieve the entity.
They both marked as @Transactional and if called will run in there own transaction.
The trigger is a plain JEE servlet which retrieves the facade from application context.
First the store method is called (tx1) then the retrieve method is called (tx2).
As you will see with the Spring hibernate4 integration there was nothing saved.
With the hibernate3 integration everything works as expected and the record is saved
(it can be retrieved by the subsequent retrieval transaction)

What is also bizarre is that in hibernate3 modus everything goes via the Spring TransactionSynchronizationManager (even in JTA mode).
Also the current session is bound via a thread local referenced via the synchronization.
This is bound using a SpringSessionSynchronization which will call flush before transaction completion.

All of this is gone with the hibernate4 integration from the moment a JTA environment is detected.
As of then everything goes via the JTA transaction manager, as there where no Spring Transacion management involved.
This could be normal to a certain extend, but it feels odd compared to the way is was done with hibernate3.

I supplied two samples:

  • hibernate3.zip : this is the working one, deploy it on GF and goto "http://localhost:8080/hibernate3/Persist"
    You will see that it stores a record and is able to retrieve it again

  • hibernate4.zip : the exact same sample as above, but now with hibernate4 and using LocalSessionFactoryBean from the hibernate4 package and the hibernate.transaction.jta.platform set.
    You will see that it stores a record and is NOT able to retrieve it.

Both samples have a POM so it should be trivial to build them.


Affects: 3.1.1

Attachments:

Issue Links:

  • #14115 Hibernate 4 smart flushing does not work unless CMTTransactionFactory is being specified ("duplicates")
  • #12571 util:map support for key-types other than String not working ("is duplicated by")
  • #14060 Spring JtaTransactionManager is not flushing during before completion phase when using Hibernate 4 or Hibernate 3 ("is duplicated by")

5 votes, 4 watchers

@spring-issuemaster

This comment has been minimized.

Copy link
Collaborator

spring-issuemaster commented May 14, 2012

Koen Serneels commented

Can someone change this to blocking please

@spring-issuemaster

This comment has been minimized.

Copy link
Collaborator

spring-issuemaster commented May 15, 2012

Erwin Vervaet commented

Is there documentation available as to how and why the Spring Hibernate integration changed between Hibernate 3 and Hibernate 4?

From the comments of #12751: "Good news: There is a working prototype already, and we decided to promote Hibernate 4.0 support to the Spring 3.1 feature set now. It won't be a direct 1:1 match with the orm.hibernate3 package but will provide everything needed for doing things the Hibernate 4 way within a Spring-based application. For example, there won't be a HibernateTemplate anymore, and we rely on Hibernate's own JTA support for JTA synchronization now."

So I have the feeling that we're missing a bit of context/explanation to setup TX management and JTA properly with Spring 3.1 + Hibernate 4.

@spring-issuemaster

This comment has been minimized.

Copy link
Collaborator

spring-issuemaster commented May 29, 2012

Erwin Vervaet commented

Seems like indeed we were missing a bit of Hibernate config. Adding the following to the Hibernate properties seems to resolve the problem:

hibernate.transaction.factory_class=org.hibernate.engine.transaction.internal.jta.JtaTransactionFactory

So this might be a non-issue as far the Spring source code is concerned, but still important in that there really is a need for a decent explanation on how to migrate your Spring + Hibernate3 config to Spring + Hibernate4. Probably something for the Spring documentation.

@spring-issuemaster

This comment has been minimized.

Copy link
Collaborator

spring-issuemaster commented May 29, 2012

Alysson Rodrigues commented

Instead of bootstrapping the entity manager factory using Spring LocalContainerEntityManagerFactory I have set JBoss AS 7.1 to bootstrap it (declaring a persistence.xml) and get it registered in JNDI, then Spring gets it from there. As soon as I have set it, everything works as expected.

Here is the persistence unit:

<persistence-unit name="persistenceUnit" transaction-type="JTA">
<jta-data-source>java:jboss/datasources/dataSourceDefault</jta-data-source>
<properties>
<property name="jboss.entity.manager.factory.jndi.name" value="java:comp/env/persistence/EntityManagerFactory"/>
<property name="hibernate.dialect" value="org.hibernate.dialect.MySQLDialect"/>
<property name="hibernate.transaction.factory_class" value="org.hibernate.engine.transaction.internal.jta.CMTTransactionFactory"/>
<property name="hibernate.transaction.jta.platform" value="org.hibernate.service.jta.platform.internal.JBossAppServerJtaPlatform"/>
<property name="hibernate.current_session_context_class" value="jta"/>
<property name="hibernate.show_sql" value="true"/>
<property name="hibernate.format_sql" value="true"/>
<property name="hibernate.use_sql_comments" value="true"/>
<property name="hibernate.hbm2ddl.auto" value="update"/>
</properties>
</persistence-unit>

The EntityManagerFactory bean:

@Bean
public EntityManagerFactory entityManagerFactory() throws NamingException {
    Context context = new InitialContext();
    EntityManagerFactory entityManagerFactory =
            (EntityManagerFactory) context.lookup("java:comp/env/persistence/EntityManagerFactory");
    return entityManagerFactory;
}

It looks like something is missing when using LocalContainerEntityManagerFactory. I have tried to use LocalContainerEntityManagerFactory.packagesToScan and it seems to me that the code (DefaultPersistenceUnitManager.buildDefaultPersistenceUnitInfo) that builds PersistenceUnitInfo is not setting the transaction-type as it should do.

By now I´ll use this approach until some news about it.

Thanks for answering me.

@spring-issuemaster

This comment has been minimized.

Copy link
Collaborator

spring-issuemaster commented Jul 16, 2012

Erwin Vervaet commented

I'm guessing this issue can be closed with #14115 having been resolved and the docs amended.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment