并发请求失败 - “会话已关闭!”

时间:2017-03-29 10:56:12

标签: java spring hibernate session concurrency

我不知道我的下面的代码有什么问题。如果我从浏览器点击我的请求,它工作正常。但是,当我发出并发请求时,它无法说会话已关闭!。我同时或同时点击以下两个网址(异步调用)。

http://localhost:8080/getEmployee
http://localhost:8080/getDepartment

Controller.java

@RequestMapping(value = "/getEmployees", method = RequestMethod.POST)
 public @ResponseBody List<Employee> getEmployee() {

        List<Employee> empList = null;
        empList = services.getEmployee();
        return empList;
    }

 @RequestMapping(value = "/getDepartments", method = RequestMethod.GET)
 public @ResponseBody List<Department> getDepartment() {

        List<Department> deptList = null;
        deptList = services.getDepartment();
        return deptList;
    }

两个模型类

Table 1 (Employee)
@Entity
@Table(name = "employee")
public class Employee implements java.io.Serializable {

    private static final long serialVersionUID = 2650114334774359089L;

    @Id
    @Column(name = "id", unique = true, nullable = false, length = 100)
    private String id;

    @Column(name = "name", unique = true, nullable = false, length = 50)
    private String name;

// getter setter

//第二个模型类

Table 2 (Department)
@Entity
@Table(name = "department")
public class Department implements java.io.Serializable {

    private static final long serialVersionUID = 2650114334774359089L;

    @Id
    @Column(name = "id", unique = true, nullable = false, length = 100)
    private String id;

    @Column(name = "dept_name", unique = true, nullable = false, length = 50)
    private String dept_name;

    // getter setter

DAOImpl

@Autowired
    SessionFactory sessionFactory;

    Session session = null;
    Transaction tx = null;

    static final Logger LOGGER = Logger.getLogger(DataDaoImpl.class);
    public List<Employee> getEmployee() throws Exception {
        List<Employee> result = null;
        session = sessionFactory.openSession();
        String hql = "from Employee";
        Query lQuery = session.createQuery(hql);
        result = lQuery.list();
        tx = session.getTransaction();
        session.beginTransaction();
        tx.commit();
        return result;
    }

    public List<Department> getDepartment() throws Exception {
        List<Department> result = null;
        session = sessionFactory.openSession();
        String hql = "from Department";
        Query lQuery = session.createQuery(hql);
        result = lQuery.list();
        tx = session.getTransaction();
        session.beginTransaction();
        tx.commit();
        return result;
    }

ServiceImpl

@Override
    public List<Employee> getEmployee() throws Exception {
        return dataDao.getEmployee();
    }

    @Override
    public List<Department> getDepartment() throws Exception {
        return dataDao.getDepartment();
    }

弹簧-config.xml中

<bean id="dataSource"
        class="org.springframework.jdbc.datasource.DriverManagerDataSource">

        <property name="driverClassName" value="com.mysql.jdbc.Driver" /> 
        <property name="url" value="jdbc:mysql://localhost:3306/mydb" />
        <property name="username" value="root" />
        <property name="password" value="password"/>
    </bean>

    <bean id="sessionFactory"
        class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
        <property name="dataSource" ref="dataSource" />
        <property name="annotatedClasses">
            <list>
                <value>com.srdh.model.Employee</value>
                <value>com.srdh.model.Department</value>

            </list>
        </property>
        <property name="hibernateProperties">
            <props>
                <prop key="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</prop>
                <prop key="hibernate.show_sql">${hibernate.show_sql}</prop>
                <prop key="hibernate.hbm2ddl.auto">update</prop>
            </props>
        </property>
    </bean>

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

    <bean id="persistenceExceptionTranslationPostProcessor"
        class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor" />

    <bean id="dataDao" class="com.test.dao.DaoImpl"></bean>
    <bean id="dataServices" class="com.test.service.ServicesImpl"></bean>

任何人都可以在我的代码中帮助我解决我的错误。我只有一个DAO来访问部门和员工表。我必须从各个表中获取记录并在输出中显示。在并发请求中它失败了。

错误堆栈跟踪

org.hibernate.HibernateException: createQuery is not valid without active transaction
    at org.hibernate.context.internal.ThreadLocalSessionContext$TransactionProtectionWrapper.invoke(ThreadLocalSessionContext.java:352)
    at com.sun.proxy.$Proxy139.createQuery(Unknown Source)
    at com.srdh.dao.DataDaoImpl.getDepartment(DataDaoImpl.java:49)
    at com.srdh.service.DataServicesImpl.getDepartment(DataServicesImpl.java:26)
    at com.srdh.controller.MainController.getDepartment(MainController.java:44)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.springframework.web.method.support.InvocableHandlerMethod.invoke(InvocableHandlerMethod.java:215)
    at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:132)
    at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:104)
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandleMethod(RequestMappingHandlerAdapter.java:749)
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:689)
    at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:83)
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:938)
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:870)
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:961)
    at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:852)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:624)
    at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:837)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:731)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:303)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
    at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:218)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:122)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:505)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:169)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:103)
    at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:958)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:116)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:452)
    at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1087)
    at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:637)
    at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:318)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
    at java.lang.Thread.run(Thread.java:745)
org.hibernate.SessionException: Session is closed!
    at org.hibernate.internal.AbstractSessionImpl.errorIfClosed(AbstractSessionImpl.java:133)
    at org.hibernate.internal.SessionImpl.beginTransaction(SessionImpl.java:1433)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.hibernate.context.internal.ThreadLocalSessionContext$TransactionProtectionWrapper.invoke(ThreadLocalSessionContext.java:356)
    at com.sun.proxy.$Proxy139.beginTransaction(Unknown Source)
    at com.srdh.dao.DataDaoImpl.Employee(DataDaoImpl.java:126)
    at com.srdh.service.DataServicesImpl.Employee(DataServicesImpl.java:71)
    at com.srdh.controller.MainController.Employee(MainController.java:73)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.springframework.web.method.support.InvocableHandlerMethod.invoke(InvocableHandlerMethod.java:215)
    at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:132)
    at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:104)
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandleMethod(RequestMappingHandlerAdapter.java:749)
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:689)
    at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:83)
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:938)
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:870)
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:961)
    at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:852)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:624)
    at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:837)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:731)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:303)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
    at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:218)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:122)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:505)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:169)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:103)
    at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:958)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:116)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:452)
    at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1087)
    at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:637)
    at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:316)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
    at java.lang.Thread.run(Thread.java:745)
org.hibernate.TransactionException: nested transactions not supported
    at org.hibernate.engine.transaction.spi.AbstractTransactionImpl.begin(AbstractTransactionImpl.java:154)
    at org.hibernate.internal.SessionImpl.beginTransaction(SessionImpl.java:1435)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)

2 个答案:

答案 0 :(得分:2)

错误堆栈跟踪显示createQuery is not valid without active transaction我们可以看到没有活动事务,换句话说没有打开事务,这是因为您创建并执行{{ 1}}在打开交易之前。

所以你最大的错误就是你在打开任何交易之前都在查询数据库。

你需要搬家:

query

在您创建和执行查询的行之前。

如果您在每个请求中使用新的tx = session.getTransaction(); session.beginTransaction(); ,则应使用Session代替sessionFactory.getCurrentSession()

所以你需要更新你的代码:

sessionFactory.openSession()

这可以解决您的问题。

注意:

正如@SergeBallesta所报告和指出的那样,你不应该在 public List<Employee> getEmployee() throws Exception { List<Employee> result = null; Session session = sessionFactory.getCurrentSession(); Transaction tx = session.getTransaction(); session.beginTransaction(); String hql = "from Employee"; Query lQuery = session.createQuery(hql); result = lQuery.list(); tx.commit(); return result; } public List<Department> getDepartment() throws Exception { List<Department> result = null; Session session = sessionFactory.getCurrentSession(); Transaction tx = session.getTransaction(); session.beginTransaction(); String hql = "from Department"; Query lQuery = session.createQuery(hql); result = lQuery.list(); tx.commit(); return result; } 中使用sessiontx作为实例变量,你最好在你的方法中使用它们作为本地变量上面的代码。

答案 1 :(得分:0)

您的DAOImpl看起来很可疑。

春豆通常是单身人士。在运行的程序中只有一个Spring bean实例。您没有发布完整的代码,但看起来您的类DAOImpl具有会话和事务的成员变量。

如果多个线程同时使用相同的单个DAOImpl对象,更改成员变量,那么它们将相互干扰。处理一个请求的线程将从另一个处理另一个请求的线程中看到会话和事务。

不要将状态(成员变量)放在单例Spring bean中。 sessiontx不应该是,也不一定是类DAOImpl中的成员变量。在方法getEmployeegetDepartment中改为使用局部变量。

更好的方法是使用Spring Data JPA而不是实现自己的DAO对象。这使得它更容易,您不必直接处理较低级别的详细信息,例如获取会话和事务。