0
votes

I have problem using simple Spring MVC Hibernate CRUD application. I use annotation Transactional in Service layer, method, calling from Service layer is DAO method, it should be wrapped in this transaction and use the same Session but it doesn't. if I open new Session - it works, but I want to work in Session, created in Session layer.

Exception: Message Request processing failed; nested exception is org.hibernate.HibernateException: Could not obtain transaction-synchronized Session for current thread

Description The server encountered an unexpected condition that prevented it from fulfilling the request.

Exception

 org.springframework.web.util.NestedServletException: Request processing failed; nested exception is org.hibernate.HibernateException: Could not obtain transaction-synchronized Session for current thread
    org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1014)
    org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:909)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:652)
    org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:733)
    org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
Root Cause

org.hibernate.HibernateException: Could not obtain transaction-synchronized Session for current thread
    org.springframework.orm.hibernate5.SpringSessionContext.currentSession(SpringSessionContext.java:143)
    org.hibernate.internal.SessionFactoryImpl.getCurrentSession(SessionFactoryImpl.java:479)
    by.itacademy.newsproject.dao.impl.SQLNewsDAOImpl.create(SQLNewsDAOImpl.java:36)
    by.itacademy.newsproject.service.impl.NewsServiceImpl.create(NewsServiceImpl.java:35)
    by.itacademy.newsproject.controller.NewsController.createNews(NewsController.java:93)
    java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    java.base/java.lang.reflect.Method.invoke(Method.java:566)
    org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:190)
    org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:138)
    org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:105)
    org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:878)
    org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:792)
    org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
    org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1040)
    org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:943)
    org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)
    org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:909)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:652)
    org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:733)
    org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
Note The full stack trace of the root cause is available in the server logs.

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" id="WebApp_ID" version="3.1">
  <display-name> project-spring-hib</display-name>

  <welcome-file-list>
    <welcome-file>index.jsp</welcome-file>
    </welcome-file-list>

    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>
            /WEB-INF/spring/application-context.xml
            /WEB-INF/spring/hibernateConfig.xml
        </param-value>
    </context-param>


    <!-- Bootstraps the root web application context before servlet initialization -->
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>


  <servlet>
    <servlet-name>dispatcher</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
     <init-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>/WEB-INF/spring/dispatcher-servlet.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
  </servlet>
  
  <servlet-mapping>
    <servlet-name>dispatcher</servlet-name>
    <url-pattern>/</url-pattern>
  </servlet-mapping>
</web-app>

application-context.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:jdbc="http://www.springframework.org/schema/jdbc"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc.xsd
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd">

        
</beans>

dispatcher-servlet.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

    <mvc:annotation-driven/>
    
    <!-- Add support for reading web resources: css, images, js, etc ... -->
        <mvc:resources location="/resources/" mapping="/resources/**"/>
    
       <!-- Specifying base package of the Components like Controller, Service,
        DAO -->
    <context:component-scan base-package="by.itacademy.newsproject.*"/>
        
            <!-- View Resolver -->
        <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
            <property name="prefix" value="/WEB-INF/view/"/>
            <property name="suffix" value=".jsp"/>
        </bean>
</beans>

hibernateConfig.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/mvc
        http://www.springframework.org/schema/mvc/spring-mvc.xsd
        http://www.springframework.org/schema/tx 
        http://www.springframework.org/schema/tx/spring-tx.xsd">

  <!-- Getting Database properties -->
    <context:property-placeholder location="classpath:hibernate.properties"/>

    <!-- Define Database DataSource / connection pool -->
    <bean id="myDataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"
          destroy-method="close">
        <property name="driverClass" value="${jdbc.driverClassName}" />
        <property name="jdbcUrl" value="${jdbc.url}" />
        <property name="user" value="${jdbc.user}" />
        <property name="password" value="${jdbc.pass}" /> 

        <!-- these are connection pool properties for C3P0 -->
        <property name="minPoolSize" value="${jdbc.minPoolSize}" />
        <property name="maxPoolSize" value="${jdbc.maxPoolSize}" />
        <property name="maxIdleTime" value="${jdbc.maxIdleTime}" />
    </bean>  
    
    <!-- Setup Hibernate session factory -->
    <bean id="mySessionFactory"
        class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
        <property name="dataSource" ref="myDataSource" />
        <property name="packagesToScan" value="by.itacademy.newsproject.entity" />
        <property name="hibernateProperties">
           <props>
              <prop key="hibernate.dialect">${hibernate.dialect}</prop>
              <prop key="hibernate.show_sql">${hibernate.show_sql}</prop>
           </props>
        </property>
   </bean>    

    <!-- Setup Hibernate transaction manager -->
    <bean id="myTransactionManager"
            class="org.springframework.orm.hibernate5.HibernateTransactionManager">
        <property name="sessionFactory" ref="mySessionFactory"/>
    </bean>
    
    <!-- Enable configuration of transactional behavior based on annotations -->
        <tx:annotation-driven transaction-manager="myTransactionManager"/>

    </beans>

News

package by.itacademy.newsproject.entity;

import java.io.Serializable;
import java.time.LocalDate;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name = "newspaper")
public class News implements Serializable {
    private static final long serialVersionUID = -4037020843129228781L;

    @Id
    @Column(name = "id")
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private int id;

    @Column(name = "date")
    private LocalDate date;

    @Column(name = "section")
    private String section;

    @Column(name = "author")
    private String author;

    @Column(name = "brief")
    private String brief;

    @Column(name = "content")
    private String content;

    public News() {
    }

    public News(int id, LocalDate date, String section, String author, String brief, String content) {
        this.id = id;
        this.date = date;
        this.section = section;
        this.author = author;
        this.brief = brief;
        this.content = content;
    }

    public News(LocalDate date, String section, String author, String brief, String content) {
        this.date = date;
        this.section = section;
        this.author = author;
        this.brief = brief;
        this.content = content;
    }

    public News(String section, String author, String brief, String content) {
        this.section = section;
        this.author = author;
        this.brief = brief;
        this.content = content;
    }

// getters, setters, equals, hashcode

Controller:

NewsController
package by.itacademy.newsproject.controller;

import java.util.ArrayList;
import java.util.List;
import javax.servlet.http.HttpSession;

import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;

import by.itacademy.newsproject.entity.News;
import by.itacademy.newsproject.entity.ParameterForm;
import by.itacademy.newsproject.service.NewsService;
import by.itacademy.newsproject.service.ServiceException;

@Controller
@RequestMapping(value = "/news")
public class NewsController {
    private static final Logger logger = Logger.getLogger(NewsController.class);

    private NewsService newsService;

    @Autowired
    public void setNewsService(NewsService newsService) {
        this.newsService = newsService;
    }

    /**
     * FILL_NEWS
     * 
     * Forwards to JSP page with form to fill data which we need to save into DB.
     * This COMMAND works together with CREATE_NEWS to finish saving News into DB.
     * 
     * Puts News object into Model to handle it inside JSP page.
     * 
     * @author 
     *
     */
    @GetMapping(value = "/fill_news")
    public String fillNews(Model model, HttpSession session) {

        News news = new News();

        session.setAttribute(ParameterSession.CURRENT_COMMAND, ParameterCommand.FILL_NEWS);

        model.addAttribute("news", news);

        return "fill_news";
    }

    /**
     * CREATE_NEWS
     * 
     * Accepts data from JSP file: section, author, brief, content. ID and DATE
     * generates automatically. Date - current server date, ID - auto increment next
     * in DAO layer.
     * <p>
     * Puts data to DB and returns status result message (RESULT_OPERATION).
     * <p>
     * Receives data from JSP form page, creates bean
     * <p>
     * Transfers bean to Service layer.
     * 
     * Creates session with message if operation successfully performed
     * 
     * <p>
     * Session value RESULT_OPERATION to save result message if operation performed
     * successfully
     * 
     * <p>
     * Session value CURRENT_COMMAND needs if locale changes on this page, the same
     * page should be displayed. Our case - WELCOME_PAGE because operation executed
     * successfully.
     * 
     * <p>
     * Uses Post/Redirect/Get
     * 
     *
     */
    @PostMapping(value = "/create_news")
    public String createNews(@ModelAttribute("news") News news, HttpSession session) {
        logger.info("createNews running, news=" + news);
        news.setDate(ParameterForm.DATE);

        try {
            newsService.create(news);

            session.setAttribute(ParameterSession.RESULT_OPERATION,
                    ParameterSession.RESULT_OPERATION_MSG_CREATE_SUCCESS);
            session.setAttribute(ParameterSession.CURRENT_COMMAND, ParameterCommand.WELCOME_PAGE);
        } catch (ServiceException e) {
            session.setAttribute(ParameterSession.RESULT_OPERATION,
                    ParameterSession.RESULT_OPERATION_MSG_CREATE_FAILED);
            logger.error("Error creating news / " + e);
        }

        return "redirect:/news/welcome_page";
    }

.......

Service:

package by.itacademy.newsproject.service.impl;

import java.util.ArrayList;
import java.util.List;

import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import by.itacademy.newsproject.dao.DAOException;
import by.itacademy.newsproject.dao.NewsDAO;
import by.itacademy.newsproject.entity.News;
import by.itacademy.newsproject.service.NewsService;
import by.itacademy.newsproject.service.ServiceException;

@Service
public class NewsServiceImpl implements NewsService {
    private static final Logger logger = Logger.getLogger(NewsServiceImpl.class);

    @Autowired
    public void setNewsDAO(NewsDAO newsDAO) {
        this.newsDAO = newsDAO;
    }

    private NewsDAO newsDAO;

    @Override
    @Transactional
    public void create(News news) throws ServiceException {


        try {
            newsDAO.create(news);
        } catch (DAOException e) {
            logger.error("Error creating news / ", e);
            throw new ServiceException(e);
        }
    }

......

DAO: SQLNewsDAOImpl

package by.itacademy.newsproject.dao.impl;

import java.util.List;

import org.apache.log4j.Logger;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.query.Query;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

import by.itacademy.newsproject.dao.DAOException;
import by.itacademy.newsproject.dao.NewsDAO;
import by.itacademy.newsproject.entity.News;
import org.springframework.transaction.annotation.Transactional;

@Repository
public class SQLNewsDAOImpl implements NewsDAO {
    private static final Logger logger = Logger.getLogger(SQLNewsDAOImpl.class);

    @Autowired
    public void setMySessionFactory(SessionFactory mySessionFactory) {
        this.mySessionFactory = mySessionFactory;
    }

    private SessionFactory mySessionFactory;

    private static final String HQL_SELECT_ALL = "from News";
    private static final String HQL_SELECT_BY_ID = "from News where id =:newsId";
    private static final String HQL_DELETE_BY_ID = "delete from News where id =:newsId";

    @Override
    public void create(News news) throws DAOException {

        // if I open new Session - it works! but I need to use Session, that opened using
        // @Transactional from preveous Service layer
        // Session currentSession = sessionFactory.openSession();
        Session currentSession = mySessionFactory.getCurrentSession();

        currentSession.saveOrUpdate(news);
    }
......
1
And 'the full stack trace of the root cause' which is 'available in the server logs' is ...? - crizzis
Thank you for quick response, but I solved problem. Spend so many hours to fix problem, but answer was easy: - Makeind

1 Answers

0
votes

Solved problem, spent to many hours with this problem but ansnwer was easy - not correct xml files. I moved

<context:component-scan base-package="by.itacademy.newsproject.*"/>
<mvc:annotation-driven />

from dispatcher-servlet.xml to hibernateConfig.xml and problem soled. But why so, still don't know why.. Now @Transactional in Service layer wrapping methods in DAO like it should be.