I’m getting the following exception when trying to use my @Service
annotated classes:
org.hibernate.HibernateException: Could not obtain transaction-synchronized Session for current thread at org.springframework.orm.hibernate4.SpringSessionContext.currentSession(SpringSessionContext.java:134) ~[spring-orm-4.1.1.RELEASE.jar:4.1.1.RELEASE] at org.hibernate.internal.SessionFactoryImpl.getCurrentSession(SessionFactoryImpl.java:1014) ~[hibernate-core-4.3.6.Final.jar:4.3.6.Final] at webapp.base.repository.GenericDaoImpl.saveOrUpdate(GenericDaoImpl.java:59) ~[base-0.0.1-SNAPSHOT-classes.jar:na] at com.example.repository.PageViewDaoImpl.saveOrUpdate(PageViewDaoImpl.java:19) ~[site-0.0.1-SNAPSHOT.jar:na] at com.example.repository.PageViewDaoImpl.saveOrUpdate(PageViewDaoImpl.java:14) ~[site-0.0.1-SNAPSHOT.jar:na] at com.example.service.PageViewServiceImpl.savePageView(PageViewServiceImpl.java:26) ~[site-0.0.1-SNAPSHOT.jar:na] at com.example.interceptor.PageViewInterceptor.preHandle(PageViewInterceptor.java:29) ~[site-0.0.1-SNAPSHOT.jar:na] at org.springframework.web.servlet.HandlerExecutionChain.applyPreHandle(HandlerExecutionChain.java:130) ~[spring-webmvc-4.1.1.RELEASE.jar:4.1.1.RELEASE] at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:938) ~[spring-webmvc-4.1.1.RELEASE.jar:4.1.1.RELEASE] at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:877) ~[spring-webmvc-4.1.1.RELEASE.jar:4.1.1.RELEASE] at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:966) [spring-webmvc-4.1.1.RELEASE.jar:4.1.1.RELEASE] at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:857) [spring-webmvc-4.1.1.RELEASE.jar:4.1.1.RELEASE] at javax.servlet.http.HttpServlet.service(HttpServlet.java:620) [servlet-api-3.0.jar:na] at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:842) [spring-webmvc-4.1.1.RELEASE.jar:4.1.1.RELEASE] at javax.servlet.http.HttpServlet.service(HttpServlet.java:727) [servlet-api-3.0.jar:na] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:303) [tomcat-catalina-7.0.52.jar:7.0.52] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208) [tomcat-catalina-7.0.52.jar:7.0.52] at org.apache.catalina.core.ApplicationDispatcher.invoke(ApplicationDispatcher.java:748) [tomcat-catalina-7.0.52.jar:7.0.52] at org.apache.catalina.core.ApplicationDispatcher.processRequest(ApplicationDispatcher.java:488) [tomcat-catalina-7.0.52.jar:7.0.52] at org.apache.catalina.core.ApplicationDispatcher.doForward(ApplicationDispatcher.java:411) [tomcat-catalina-7.0.52.jar:7.0.52] at org.apache.catalina.core.ApplicationDispatcher.forward(ApplicationDispatcher.java:338) [tomcat-catalina-7.0.52.jar:7.0.52] at org.apache.catalina.core.StandardHostValve.custom(StandardHostValve.java:466) [tomcat-catalina-7.0.52.jar:7.0.52] at org.apache.catalina.core.StandardHostValve.status(StandardHostValve.java:337) [tomcat-catalina-7.0.52.jar:7.0.52] at org.apache.catalina.core.StandardHostValve.throwable(StandardHostValve.java:427) [tomcat-catalina-7.0.52.jar:7.0.52] at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:200) [tomcat-catalina-7.0.52.jar:7.0.52] at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:98) [tomcat-catalina-7.0.52.jar:7.0.52] at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:950) [tomcat-catalina-7.0.52.jar:7.0.52] at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:116) [tomcat-catalina-7.0.52.jar:7.0.52] at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:408) [tomcat-catalina-7.0.52.jar:7.0.52] at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1040) [tomcat-coyote-7.0.52.jar:7.0.52] at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:607) [tomcat-coyote-7.0.52.jar:7.0.52] at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:313) [tomcat-coyote-7.0.52.jar:7.0.52] at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145) [na:1.7.0_65] at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615) [na:1.7.0_65] at java.lang.Thread.run(Thread.java:745) [na:1.7.0_65]
The way I initialize my application is complicated so I need to provide a link to the full base code to get additional information: https://github.com/dtrunk90/webapp-base. I’m using this as a maven overlay.
And here is the necessary code:
Initializer (from webapp-base):
public abstract class AbstractWebApplicationInitializer extends AbstractDispatcherServletInitializer { @Override protected String[] getServletMappings() { return new String[] {"/*"}; } @Override protected Filter[] getServletFilters() { CharacterEncodingFilter encodingFilter = new CharacterEncodingFilter(); encodingFilter.setEncoding("UTF-8"); encodingFilter.setForceEncoding(true); return new Filter[] {encodingFilter}; } @Override protected WebApplicationContext createRootApplicationContext() { AnnotationConfigWebApplicationContext rootContext = new AnnotationConfigWebApplicationContext(); ConfigurableEnvironment environment = rootContext.getEnvironment(); environment.setDefaultProfiles("production"); PropertyUtil propertyUtil = PropertyUtil.getInstance(environment.getActiveProfiles()); String[] basePackages = propertyUtil.getPropertySplitTrimmed("webapp", "basePackages"); rootContext.scan(basePackages); return rootContext; } @Override protected WebApplicationContext createServletApplicationContext() { return new AnnotationConfigWebApplicationContext(); } }
Initializer (from my webapp):
public class WebApplicationInitializer extends AbstractWebApplicationInitializer { }
@Configuration
(from webapp-base):
@Configuration @EnableTransactionManagement public class TransactionConfiguration { @Bean public DataSource dataSource() throws IOException { Properties conProps = PropertyUtil.getInstance().getProperties("jdbc"); if (conProps.containsKey("url")) { DriverManagerDataSource dataSource = new DriverManagerDataSource(conProps.getProperty("url"), conProps); dataSource.setDriverClassName(conProps.getProperty("driverClassName")); return dataSource; } return null; } @Bean public SessionFactory sessionFactory() throws IOException { DataSource dataSource = dataSource(); if (dataSource != null) { LocalSessionFactoryBuilder sessionBuilder = new LocalSessionFactoryBuilder(dataSource); sessionBuilder.scanPackages(PropertyUtil.getInstance().getPropertySplitTrimmed("hibernate", "packagesToScan")); sessionBuilder.addProperties(PropertyUtil.getInstance().getProperties("hibernate")); return sessionBuilder.buildSessionFactory(); } return null; } @Bean public HibernateTransactionManager transactionManager() throws IOException { SessionFactory sessionFactory = sessionFactory(); if (sessionFactory == null) { return null; } return new HibernateTransactionManager(sessionFactory); } }
@Configuration
(from my webapp):
@Configuration public class MainConfiguration extends WebMvcConfigurerAdapter { @Autowired private PageViewInterceptor pageViewInterceptor; // Is annotated with @Component @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(pageViewInterceptor); } }
@Service
:
@Service public class PageViewServiceImpl implements PageViewService { @Autowired private PageViewDao pageViewDao; @Override public void savePageView(long ip, String visitPage, String userAgent) { PageView obj = new PageView(); obj.setVisitDate(new Date()); obj.setUserAgent(userAgent); obj.setPage(visitPage); obj.setIp(ip); pageViewDao.saveOrUpdate(obj); } }
@Repository
:
@Repository public class PageViewDaoImpl extends GenericDaoImpl<PageView, Long> implements PageViewDao { @Override public void saveOrUpdate(PageView obj) { if (!obj.isBot()) { super.saveOrUpdate(obj); } } } public abstract class GenericDaoImpl<T extends Identifier<I>, I extends Serializable> implements GenericDao<T, I> { @Autowired private SessionFactory sessionFactory; public SessionFactory getSessionFactory() { if (sessionFactory == null) { throw new IllegalStateException("SessionFactory has not been set on DAO before usage"); } return sessionFactory; } @Transactional public void saveOrUpdate(T obj) { getSessionFactory().getCurrentSession().saveOrUpdate(obj); } }
Then I’m autowiring PageViewService
and use its methods.
I know there are several questions with the same problem here but I already checked anything:
Could not obtain transaction-synchronized Session for current thread
@EnableTransactionManagement
is provided- Services wil be autowired as interfaces
HibernateException: Could not obtain transaction-synchronized Session for current thread
- Checked for
@Transactional
everywhere I usegetSessionFactory().getCurrentSession()
Spring Hibernate – Could not obtain transaction-synchronized Session for current thread
@EnableTransactionManagement
is provided- Checked for
@Transactional
everywhere I usegetSessionFactory().getCurrentSession()
- There’s no helpful answer. I want component scanning for all my components, not only controller
Advertisement
Answer
Looking at your log I can instantly tell that your transaction settings are wrongly set. That’s because there’s no TransactionInterceptor
call in your stack trace.
The TransactionInterceptor
is called by your Spring Service proxies when your web controllers call the actual Service methods.
Make sure you use the Spring hibernate4 classes:
org.springframework.orm.hibernate4.HibernateTransactionManager
Don’t override
@Transactional
methods, but use a template patterns instead.Try using
JPATransactionManager
instead so you can inject the currentEntityManager
with the@PersistenceContext
annotation instead. This is much more elegant than callingsessionFactory.getCurrentSession()
in every DAO method.