jchitel
jchitel

Reputation: 3169

Hibernate - Is there any particular reason that an @Transactional isn't working?

I have a service that requires a session to create a SQL query and then to execute it. That is all. I have an @Transactional on the top-level method and this still ends up happening:

org.hibernate.HibernateException: No Hibernate Session bound to thread, and configuration does not allow creation of non-transactional one here
     at org.springframework.orm.hibernate3.SpringSessionContext.currentSession(SpringSessionContext.java:63)
     at org.hibernate.impl.SessionFactoryImpl.getCurrentSession(SessionFactoryImpl.java:687)
     at dao.DaoRunner.getCurrentSession(DaoRunner.java:109)
     at dao.DaoRunner.createSQLQuery(DaoRunner.java:170)
     at dao.DaoRunner$$FastClassByCGLIB$$902af9f8.invoke(<generated>)
     at org.springframework.internal.cglib.proxy.MethodProxy.invoke(MethodProxy.java:149)
     at org.springframework.aop.framework.Cglib2AopProxy$DynamicAdvisedInterceptor.intercept(Cglib2AopProxy.java:618)
     at dao.DaoRunner$$EnhancerByCGLIB$$484f17ac.createSQLQuery(<generated>)
     at SOME OTHER CLASSES
     at org.apache.catalina.valves.SSLValve.invoke(SSLValve.java:113)
     at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:286)
     at org.apache.coyote.http11.Http11NioProcessor.process(Http11NioProcessor.java:894)
     at org.apache.coyote.http11.Http11NioProtocol$Http11ConnectionHandler.process(Http11NioProtocol.java:728)
     at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:2108)
     at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
     at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
     at java.lang.Thread.run(Thread.java:745)

The DaoRunner class is AutoWired by Spring, and contains the session factory. Here is the createSQLQuery method:

public Query createSQLQuery(final String sql) {
    return getCurrentSession().createSQLQuery(sql);
}

and here is the getCurrentSession() method:

public Session getCurrentSession() throws HibernateException {
    if (null == sessionFactory) {
        throw new HibernateException(
                "SessionFactory in DaoRunner is not wired.");
    }
    return sessionFactory.getCurrentSession();
}

My top level method is:

@Transactional
public Result run() {
    try {
        String inputData = input.getInputData();

        Result result = aClass.doSomething(inputData);

        return result;
    } catch (Exception e) {
        String msg = ERROR_PREFIX + e;
        StringWriter sw = new StringWriter();
        e.printStackTrace(new PrintWriter(sw));
        String stackTrace = sw.toString();
        log.error(stackTrace);
        throw new PermanentException(msg);
    }
}

Here are the sessionFactory beans:

 <bean id="AbstractSessionFactory"
        class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean"
        abstract="true">
   <property name="packagesToScan">
     <list>
       <value>apackage</value>
     </list>
   </property>
   <property name="exposeTransactionAwareSessionFactory">
     <value>true</value>
   </property>
 </bean>

<bean id="sessionFactory"
      class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean"
      parent="AbstractSessionFactory" depends-on="AppConfigHelper">
    <property name="hibernateProperties">
      <props>
         <prop key="hibernate.connection.provider_class">org.hibernate.connection.C3P0ConnectionProvider</prop>
         <prop key="hibernate.connection.pool_size">12</prop>             
         <prop key="hibernate.connection.driver_class">${OCF.JDBC.driverClassName}</prop>
         <prop key="hibernate.connection.url">${OCF.JDBC.databaseURL}</prop>
         <prop key="hibernate.connection.username">${OCF.JDBC.databaseUsername}</prop>
         <prop key="hibernate.connection.password">${OCF.JDBC.databasePassword}</prop>

         <prop key="hibernate.dialect">org.hibernate.dialect.OracleDialect</prop>
         <prop key="hibernate.default_schema">${default.schema}</prop>

         <prop key="hibernate.jdbc.batch_size">1000</prop> 
         <prop key="hibernate.show_sql">false</prop>
         <prop key="hibernate.format_sql">false</prop>

         <prop key="hibernate.c3p0.timeout">44000 <!-- seconds --></prop>

         <prop key="hibernate.c3p0.min_size">#{ '5'}</prop>
         <prop key="hibernate.c3p0.max_size">#{ '5'}</prop>
         <prop key="hibernate.c3p0.initial_pool_size">#{ '5'}</prop>
         <prop key="hibernate.c3p0.idle_test_period">#{  '60'}</prop>
         <prop key="hibernate.c3p0.acquire_increment">#{'2'}</prop>
         <prop key="hibernate.c3p0.max_statements">50</prop>

         <prop key="hibernate.connection.oracle.jdbc.ReadTimeout">60000</prop>
      </props>
    </property>
</bean>

<tx:annotation-driven transaction-manager="txManager" proxy-target-class="true" />

 <bean id="txManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
   <property name="sessionFactory" ref="sessionFactory" />
 </bean>

Note that I didn't write most of this. I added my top-level method and the createSQLQuery() method.

Upvotes: 1

Views: 240

Answers (2)

Kevin Bowersox
Kevin Bowersox

Reputation: 94469

The run method annotated with @Transactional must be invoked on a bean that is registered within the IOC container.

To make this class a bean you can register it within your XML configuration or simply annotate the class with the @Component annotation and setup component scanning within your XML configuration. Then inject the bean from the container and call the run method.

Simply put, the run method needs to invoked from a bean injected from the IOC container.

Upvotes: 3

user3487063
user3487063

Reputation: 3682

you need to have transaction manager setup in spring config, something like below:

<!-- Enable Annotations for Transaction Management -->
    <tx:annotation-driven transaction-manager="transactionManager" />

    <!-- Creating TransactionManager, change class based on your requirement. -->
    <bean id="transactionManager"
        class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource" />
    </bean>

Upvotes: 1

Related Questions