Problem with transactions: No Hibernate Session bound to thread
I refactored my service layer to work as generic component. After that all request to my controller began to throw org.hibernate.HibernateException: No Hibernate Session bound to thread, and configuration does not allow creation of non-transactional one here.
I searched over the internet and found common reasons:
- Lack of @Transaction annotation.
- Usage of hibernate.current_session_context_class and hibernate.transaction_factory_class options.
- Direct calls to sessionFactory.openSession().
- Using BeanFactory instead of ApplicationContext.
- Several instances of DAO class.
But it seems that none of them are related to my case.
I would appreciate any help as I've spent all my day with this exception.
Stacktrace
[INFO] 2011-08-12 15:42:49,383 [btpool0-0] INFO ru.centr_in.rescuer.server.web.InfoJournalController - FETCH started: all
[INFO] 2011-08-12 15:42:49,383 [btpool0-0] DEBUG org.springframework.orm.hibernate3.SessionFactoryUtils - Opening Hibernate Session
[INFO] 2011-08-12 15:42:49,383 [btpool0-0] DEBUG org.hibernate.impl.SessionImpl - opened session at timestamp: 13131493693
[INFO] 2011-08-12 15:42:49,383 [btpool0-0] DEBUG org.springframework.orm.hibernate3.SessionFactoryUtils - Closing Hibernate Session
[INFO] 2011-08-12 15:42:49,383 [btpool0-0] DEBUG org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerExceptionResolver - Resolving exception from handler [ru.centr_in.rescuer.server.web.InfoJournalController@14e1b74]: org.hibernate.HibernateException: No Hibernate Session bound to thread, and configuration does not allow creation of non-transactional one here
[INFO] 2011-08-12 15:42:49,384 [btpool0-0] DEBUG org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver - Resolving exception from handler [ru.centr_in.rescuer.server.web.InfoJournalController@14e1b74]: org.hibernate.HibernateException: No Hibernate Session bound to thread, and configuration does not allow creation of non-transactional one here
[INFO] 2011-08-12 15:42:49,384 [btpool0-0] DEBUG org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver - Resolving exception from handler [ru.centr_in.rescuer.server.web.InfoJournalController@14e1b74]: org.hibernate.HibernateException: No Hibernate Session bound to thread, and configuration does not allow creation of non-transactional one here
[INFO] 2011-08-12 15:42:49,384 [btpool0-0] DEBUG org.springframework.web.servlet.DispatcherServlet - Could not complete request
[INFO] org.hibernate.HibernateException: No Hibernate Session bound to thread, and configuration does not allow creation of non-transactional one here
[INFO] at org.springframework.orm.hibernate3.SpringSessionContext.currentSession(SpringSessionContext.java:63)
[INFO] at org.hibernate.impl.SessionFactoryImpl.getCurrentSession(SessionFactoryImpl.java:574)
[INFO] at ru.centr_in.rescuer.server.dao.HibernateGenericDao.findAll(HibernateGenericDao.java:41)
[INFO] at ru.centr_in.rescuer.server.service.AbstractCRUDServiceBean.findAll(AbstractCRUDServiceBean.java:21)
[INFO] at ru.centr_in.rescuer.server.web.InfoJournalController.getInfoJournalEntries(InfoJournalController.java:40)
[INFO] at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
[INFO] at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
[INFO] at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
[INFO] at java.lang.reflect.Method.invoke(Method.java:597)
[INFO] at org.springframework.web.bind.annotation.support.HandlerMethodInvoker.invokeHandlerMethod(HandlerMethodInvoker.java:176)
[INFO] at org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.invokeHandlerMethod(AnnotationMethodHandlerAdapter.java:426)
[INFO] at org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.handle(AnnotationMethodHandlerAdapter.java:414)
[INFO] at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:790)
[INFO] at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:719)
[INFO] at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:644)
[INFO] at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:549)
[INFO] at javax.servlet.http.HttpServlet.service(HttpServlet.java:617)
[INFO] at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
[INFO] at org.mortbay.jetty.servlet.ServletHolder.handle(ServletHolder.java:487)
[INFO] at org.mortbay.jetty.servlet.ServletHandler.handle(ServletHandler.java:362)
[INFO] at org.mortbay.jetty.security.SecurityHandler.handle(SecurityHandler.java:216)
[INFO] at org.mortbay.jetty.servlet.SessionHandler.handle(SessionHandler.java:181)
[INFO] at org.mortbay.jetty.handler.ContextHandler.handle(ContextHandler.java:729)
[INFO] at org.mortbay.jetty.webapp.WebAppContext.handle(WebAppContext.java:405)
[INFO] at org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:152)
[INFO] at org.mortbay.jetty.handler.RequestLogHandler.handle(RequestLogHandler.java:49)
[INFO] at org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:152)
[INFO] at org.mortbay.jetty.Server.handle(Server.java:324)
[INFO] at org.mortbay.jetty.HttpConnection.handleRequest(HttpConnection.java:505)
[INFO] at org.mortbay.jetty.HttpConnection$RequestHandler.headerComplete(HttpConnection.java:829)
[INFO] at org.mortbay.jetty.HttpParser.parseNext(HttpParser.java:513)
[INFO] at org.mortbay.jetty.HttpParser.parseAvailable(HttpParser.java:211)
[INFO] at org.mortbay.jetty.HttpC开发者_运维问答onnection.handle(HttpConnection.java:380)
[INFO] at org.mortbay.io.nio.SelectChannelEndPoint.run(SelectChannelEndPoint.java:395)
[INFO] at org.mortbay.thread.QueuedThreadPool$PoolThread.run(QueuedThreadPool.java:488)
Controller
@Controller
public class InfoJournalController {
@Autowired
private InfoJournalService infoJournalService;
@RequestMapping(value="/infoJournal", method=RequestMethod.GET)
public @ResponseBody InfoJournalEntry[] getInfoJournalEntries() {
List<InfoJournalEntry> entries = infoJournalService.findAll();
InfoJournalEntry[] result = new InfoJournalEntry[entries.size()];
entries.toArray(result);
return result;
}
}
Generic service interface
public interface AbstractCRUDService<E, PK extends Serializable> {
void save(E entity);
List<E> findAll();
E findById(PK id);
void delete(E entity);
void update(E entity);
}
Generic service implementation
@Transactional
public abstract class AbstractCRUDServiceBean<E, PK extends Serializable> implements AbstractCRUDService<E, PK> {
//....
@Transactional
public List<E> findAll() {
return getDao().findAll();
}
//....
public abstract AbstractDao<E, PK> getDao();
}
Concrete service interface
public interface InfoJournalService extends AbstractCRUDService<InfoJournalEntry, Long> }
Concrete service implementation
@Service("infoJournalService")
public class InfoJournalServiceImpl extends AbstractCRUDServiceBean<InfoJournalEntry, Long> implements InfoJournalService {
@Autowired
private InfoJournalDao infoJournalDao;
@Override
public AbstractDao<InfoJournalEntry, Long> getDao() {
return infoJournalDao;
}
}
Generic DAO interface
public abstract class HibernateGenericDao<E, PK extends Serializable> implements AbstractDao<E, PK> {
@Autowired
protected SessionFactory sessionFactory;
//....
@SuppressWarnings("unchecked")
public List<E> findAll() {
return sessionFactory.getCurrentSession().createCriteria(getEntityClass()).list();
}
public abstract Class getEntityClass();
}
Generic DAO implementation public abstract class HibernateGenericDao implements AbstractDao {
@Autowired
protected SessionFactory sessionFactory;
//....
@SuppressWarnings("unchecked")
public List<E> findAll() {
return sessionFactory.getCurrentSession().createCriteria(getEntityClass()).list();
}
public abstract Class getEntityClass();
}
Concrete DAO implementation
@Repository("infoJournalDao")
public class InfoJournalDaoImpl extends HibernateGenericDao<InfoJournalEntry, Long> implements InfoJournalDao {
@Override
public Class getEntityClass() {
return InfoJournalEntry.class;
}
}
root-context.xml
<context:annotation-config />
<context:component-scan base-package="ru.centr_in.rescuer.server" />
<import resource="datasource.xml" />
datasource.xml
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager" >
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<tx:annotation-driven transaction-manager="transactionManager"/>
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location">
<value>WEB-INF/database.properties</value>
</property>
</bean>
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${jdbc.driverClassName}" />
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="configurationClass">
<value>org.hibernate.cfg.AnnotationConfiguration</value>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.hbm2ddl.auto">create</prop>
<prop key="hibernate.dialect">${jdbc.dialect}</prop>
<prop key="hibernate.connection.charset">UTF-8</prop>
</props>
</property>
<property name="annotatedClasses">
<list>
<value>ru.centr_in.rescuer.server.domain.InfoJournalEntry</value>
</list>
</property>
</bean>
servlet-context.xml
<annotation-driven/>
<context:component-scan base-package="ru.centr_in.rescuer.server" />
<resources mapping="/resources/**" location="/resources/"/>
<resources mapping="/Rescuer.html" location="/Rescuer.html"/>
<resources mapping="/Rescuer/**" location="/Rescuer/"/>
<beans:bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<beans:property name="prefix" value="/WEB-INF/views/"/>
<beans:property name="suffix" value=".jsp"/>
</beans:bean>
It seems I've found my mistake.
Both root-context.xml
and servlet-context.xml
contain the same line <context:component-scan base-package="ru.centr_in.rescuer.server" />
.
Now I specified base packages in the following way:
root-context.xml
<context:component-scan base-package="ru.centr_in.rescuer.server.service" />
<context:component-scan base-package="ru.centr_in.rescuer.server.dao" />
and servlet-context.xml
<context:component-scan base-package="ru.centr_in.rescuer.server.web" />
And now everything works.
Thanks to Miles from Entities Not Persisting - Spring + Hibernate + JPA
Spring recommends that you only annotate concrete classes (and methods of concrete classes) with the @Transactional
annotation, as opposed to annotating interfaces.
Have you tried putting the @Transactional
annotation on the InfoJournalServiceImpl
class? Also, have you checked that you have a <tx:annotation-driven transaction-manager="..." />
in your spring config, as explained in the Spring documentation?
精彩评论