WAS 6.1, JPA with JTA, Hibernate, Spring : data retrieval problem
I'm running an application with the following components:
- Oracle 9i
- WAS 6.1.0.23 with WS and EJB3 features pack
- JPA with Hibernate 3.3.2.GA as provider (with Hibernate-EntityManager 3.4.0)
- Spring transaction manager for WAS : UowTransactionManager (spring 2.5.6)
- Spring webflow with flow-managed persistence (2.0.8), i.e. the entity manager is serialized into the http session, and restored on each request.
In each request going from the web controller to the service layer (annotated with Spring's @Transactional), I have noticed that for each SQL query that Hibernate performs during the service invocation inside the transaction, a new DataSource connnection is requested from the jndi DataSource by Hibernate's ConnectionProvider, until the DataSource runs out of free connections and eventually hangs.
Here are parts of the configuration:
Spring:
<tx:annotation-driven /> <context:component-scan base-package="org.home.myapp" /> <jee:jndi-lookup id="dataSource" jndi-name="jdbc/DS" resource-ref="true"/> <bean id="transactionManager" class="org.springframework.transaction.jta.WebSphereUowTransactionManager"/> <bean id="EMF" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> <property name="dataSource" ref="dataSource"/> <property name="jpaVendorAdapter"> <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"/> </property> </bean>
persistence.xml
<persistence-unit name="persistence" transaction-type="JTA"> <properties> <property name="hibernate.archive.autodetection" value="class"/> <property name="hibernate.dialect" value="org.hibernate.dialect.Oracle9iDialect"/> <property name="hibernate.current_session_context_class" value="jta"/> <property name="hibernate.cache.provider_class" value="org.hibernate.cache.NoCacheProvider"/> <property name="hibernate.format_sql" value="true"/> <property name="hibernate.show_sql" value="true"/> <property name="hibernate.default_batch_fetch_size" value="20"/> <property name="hibernate.transacti开发者_C百科on.manager_lookup_class" value="org.hibernate.transaction.WebSphereExtendedJTATransactionLookup"/> </properties> </persistence-unit>
Service
@Transactional(readOnly=true) @Service public class MyServiceImpl implements MyService { @Autowired MyDao dao; public void getSomething() { dao.findSomething(); } }
DAO
@Repository public class MyDaoJap implements MyDao { @PersistenceContext EntityManager em; public void findSomething() { em.find(...); } }
Note the transaction is read-only, which is normal for flow-persistence: only the last transition (with commit=true) invokes a non-readOnly transactional method. Turning on the readOnly flag automatically turns Hibernate flush mode to MANUAL.
While doing some debug, I noticed the following:
- The UOW transaction manager is correctly invoked in the interception chain of the service, which suggests that a transaction is active
- Hibernate asks for a connection by invoking DataSource.getConnection() on the raw DataSource that is injected into the EMF; The strategy for getting a connection is from Hibernate's InjectedDataSourceConnectionProvider, and this class references the WAS DataSource (not a proxy that is aware of an active transaction, or such).
I guess the problem is in this second point, but I can't find an error in my configuration. Can anybody help ?
Thanks for your help.
some wild guesses from our config
- hibernate prop - hibernate.connection.release_mode=after_statement
- web.xml resource ref datasource config - <res-sharing-scope>Shareable</res-sharing-scope>
- spring sessionFactory config - useTransactionAwareDataSource="true"
it even might be a configuration issue inside was
I think (and hope) that your problems stems from the fact that by using the dataSource property it defaults to a "nonJtaDataSource". The default (simple) configuration is really optimised for lower grade transactional systems (tomcat/SE) and not the more hardcore stack that you're using.
You're going to need to configure the entity manager factory to have a jta datasource. The way that I did this is to create my own JtaPersistenceUnitPostProcessor where I could set this up.
By doing it this way I was able to set the EMF to use a JtaDatasource, I'm not sure if there is a better way of doing this. You could simply, as a POC add the jta datasource reference to your persistence.xml.
精彩评论