views:

1483

answers:

3

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:

  1. 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>
    
  2. 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.transaction.manager_lookup_class" value="org.hibernate.transaction.WebSphereExtendedJTATransactionLookup"/>   
      </properties>
    </persistence-unit>
    
  3. Service

    @Transactional(readOnly=true) @Service
    public class MyServiceImpl implements MyService {
      @Autowired MyDao dao;
      public void getSomething() {
        dao.findSomething();
      }
    }
    
  4. 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.

A: 

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.

Michael Wiles
Looking at Spring code for DefaultPersistenceUnitManager and PersistenceUnitReader, I noticed that the DataSource that is injected into the LocalContainerEntityManagerFactoryBean is used as-is to define the jta- and non-jta-datasource of the persistence unit (if such a corresponding element is declared in persistence.xml, with whatever value). Eventually, if no non-jta-data-source element is specified in the PU, that same datasource is injected as the non-jta-datasource.Thus, I added a jta-data-source element in my persistence.xml, and it still behaves the same.
Gaetan
Spring provides 3 implementations for Hibernate's ConnectionProvider interface: LocalDataSourceConnectionProvider and 2 subclasses, LocalJtaDataSourceConnectionProvider and TransactionAwareDataSourceConnectionProvider; they're all in orm.hibernate3 package (not jpa), this I don't think they should be used for JPA. When running my app, the connection provider that is configured is Hibernate's InjectedDataSourceConnectionProvider; I would expect some kind of transaction-aware DataSource (unless transaction is entirely delegated to WAS DataSource)...
Gaetan
A: 

Did you find the solution to this problem. Iam also having the same issue.

ramana
IMHO that should have been a comment rather than an answer.
beny23
+1  A: 

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

Michael Lange
2nd is the correct answer. The sharing scope of the DataSource was Unsharable.Thanks a lot.
Gaetan