Reputation: 3169
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
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
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