【问题标题】:Could not commit Hibernate transaction无法提交休眠事务
【发布时间】:2018-05-06 16:27:50
【问题描述】:

我是 Hibernate 的新手。我正在尝试编写一种方法来插入或更新 50 条记录,然后提交它,然后再次继续插入。我这样做是因为如果在插入最后一条记录时发生了一些事情,我想在数据库中保留所有以前的记录。

这就是我正在做的:

@Override
    public boolean updateStoreDetails(List<StoreDetailsDTO> storeDetailsDTOs){
        Session session = this.hibernateSessionFactory.getCurrentSession();
        int count = 0;
        boolean sessionEnded =false;

        for(StoreDetailsDTO storeDetailsDTOTmp : storeDetailsDTOs){
            if(sessionEnded){//At the very beginning, the transaction remains open dont know why. So  session.getTransaction().begin() causing exception
                session.getTransaction().begin();
                sessionEnded = false;
            }
            session.saveOrUpdate(storeDetailsDTOTmp);
            if ( ++count % 10 == 0 ) {      //If batch size is 50 clear session-level cache & to avoid OutOfMemoryException
                  logger.info("Clearing session after 50 batch size. Total rows inserted/updated till now: "+ count);
                  session.getTransaction().commit();
                  session.flush();
                  session.clear();
                  sessionEnded =true;

            } else if(count == storeDetailsDTOs.size()){
               session.getTransaction().commit();
               session.flush();
               session.clear();
            }
        }
        logger.info("Insertion completed. Total rows inserted/updated: "+ count);
        return true;
    }

这工作正常,但在执行此方法后发生异常。由于这个原因,该方法的返回值从未返回给调用方法。谁能帮我?堆栈跟踪:

com.follett.fd.exception.UniversityWithSimilarAdoptionException: Could not commit Hibernate transaction; nested exception is org.hibernate.TransactionException: Transaction not successfully started
    at com.follett.fd.service.impl.FFDServiceImpl.populateLocation(FFDServiceImpl.java:194) ~[classes/:na]
    at com.follett.fd.controller.FFDServiceController.populateLocation(FFDServiceController.java:74) ~[classes/:na]
    at com.follett.fd.controller.FFDServiceController$$FastClassBySpringCGLIB$$2f892fae.invoke(<generated>) ~[classes/:na]
    at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204) ~[spring-core-4.2.4.RELEASE.jar:4.2.4.RELEASE]
    at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:720) ~[spring-aop-4.2.4.RELEASE.jar:4.2.4.RELEASE]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157) ~[spring-aop-4.2.4.RELEASE.jar:4.2.4.RELEASE]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:173) ~[spring-aop-4.2.4.RELEASE.jar:4.2.4.RELEASE]
    at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92) ~[spring-aop-4.2.4.RELEASE.jar:4.2.4.RELEASE]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) ~[spring-aop-4.2.4.RELEASE.jar:4.2.4.RELEASE]
    at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:655) ~[spring-aop-4.2.4.RELEASE.jar:4.2.4.RELEASE]
    at com.follett.fd.controller.FFDServiceController$$EnhancerBySpringCGLIB$$f350f456.populateLocation(<generated>) ~[classes/:na]
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_25]
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_25]
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_25]
    at java.lang.reflect.Method.invoke(Method.java:483) ~[na:1.8.0_25]
    at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:222) ~[spring-web-4.2.4.RELEASE.jar:4.2.4.RELEASE]
    at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:137) ~[spring-web-4.2.4.RELEASE.jar:4.2.4.RELEASE]
    at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:110) ~[spring-webmvc-4.2.4.RELEASE.jar:4.2.4.RELEASE]
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:814) ~[spring-webmvc-4.2.4.RELEASE.jar:4.2.4.RELEASE]
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:737) ~[spring-webmvc-4.2.4.RELEASE.jar:4.2.4.RELEASE]
    at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85) ~[spring-webmvc-4.2.4.RELEASE.jar:4.2.4.RELEASE]
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:959) ~[spring-webmvc-4.2.4.RELEASE.jar:4.2.4.RELEASE]
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:893) ~[spring-webmvc-4.2.4.RELEASE.jar:4.2.4.RELEASE]
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:969) [spring-webmvc-4.2.4.RELEASE.jar:4.2.4.RELEASE]
    at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:871) [spring-webmvc-4.2.4.RELEASE.jar:4.2.4.RELEASE]
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:641) [tomcat-embed-core-7.0.30.jar:7.0.30]
    at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:845) [spring-webmvc-4.2.4.RELEASE.jar:4.2.4.RELEASE]
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:722) [tomcat-embed-core-7.0.30.jar:7.0.30]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:305) [tomcat-embed-core-7.0.30.jar:7.0.30]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210) [tomcat-embed-core-7.0.30.jar:7.0.30]
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:222) [tomcat-embed-core-7.0.30.jar:7.0.30]
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:123) [tomcat-embed-core-7.0.30.jar:7.0.30]
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:472) [tomcat-embed-core-7.0.30.jar:7.0.30]
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:168) [tomcat-embed-core-7.0.30.jar:7.0.30]
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:99) [tomcat-embed-core-7.0.30.jar:7.0.30]
    at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:929) [tomcat-embed-core-7.0.30.jar:7.0.30]
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118) [tomcat-embed-core-7.0.30.jar:7.0.30]
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:407) [tomcat-embed-core-7.0.30.jar:7.0.30]
    at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1002) [tomcat-embed-core-7.0.30.jar:7.0.30]
    at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:585) [tomcat-embed-core-7.0.30.jar:7.0.30]
    at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:310) [tomcat-embed-core-7.0.30.jar:7.0.30]
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) [na:1.8.0_25]
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) [na:1.8.0_25]
    at java.lang.Thread.run(Thread.java:745) [na:1.8.0_25]

【问题讨论】:

  • 仅供参考,这与 JPA API 无关

标签: java spring hibernate hibernate-mapping


【解决方案1】:

仅当sessionEndedtrue 时才打开会话,但仅在session.getTransaction().commit() 之后才将其设置为true。更好的解决方案是在循环外开始和结束会话。

【讨论】:

    【解决方案2】:

    我已将@Transactional 放在班级级别。我相信这是导致问题的原因,但我不确定。删除它后,我在执行时遇到了一些错误:this.hibernateSessionFactory.getCurrentSession();。我想我必须为此设置一个属性。

    无论如何要达到我想要的我修改了方法:

    @Override
        public boolean updateStoreDetails(List<StoreDetailsDTO> storeDetailsDTOs){
            Session session = this.hibernateSessionFactory.getCurrentSession();
            int count = 0;
            boolean sessionEnded =false;
            
            for(StoreDetailsDTO storeDetailsDTOTmp : storeDetailsDTOs){         
                session.saveOrUpdate(storeDetailsDTOTmp);
                //session.evict(storeDetailsDTOTmp);
                if ( ++count % 50 == 0 ) {      //If batch size is 50 clear session-level cache & to avoid OutOfMemoryException
                      logger.info("Clearing session after 50 batch size.");               
                      session.flush();
                      session.clear();                
                } 
            }       
            return true;
        }
    

    我在插入 50 条记录后调用此方法。请注意,我在修改方法后将@Transactional 注释保留在类级别。

    【讨论】:

      【解决方案3】:

      这是代码,您可以在 50 条记录后将记录刷新到数据库中,但在失败的情况下全部提交/回滚,这通常是这种情况,但如果您想提交 50 条记录,则在清除后执行提交。

          public void insert(List<T> items) {
      
          //begin transaction
          for (int i = 0; i < items.size(); i++) {
              T item = items.get(i);
              session.save(item);
              if (i % 50 == 0) {
                  session.flush();
                  session.clear();
              }           
          }
          session.flush();
          session.clear();
      
          //commit transaction
      }
      

      【讨论】:

        【解决方案4】:

        标志检查出现错误,导致交易无法开始。我已经进行了更改,希望这会奏效。

        @Override 
        public boolean updateStoreDetails(List<StoreDetailsDTO> storeDetailsDTOs)
        { 
        Session session = this.hibernateSessionFactory.getCurrentSession(); 
        int count = 0; 
        boolean sessionEnded =true; for(StoreDetailsDTO storeDetailsDTOTmp : storeDetailsDTOs)
        { 
        if(sessionEnded)
        {
         session.getTransaction().begin(); sessionEnded = false;
         } session.saveOrUpdate(storeDetailsDTOTmp) ; 
        if ( ++count % 10 == 0 ) 
        { 
        //If batch size is 50 clear session-level cache & to avoid OutOfMemoryException 
        logger.info("Clearing session after 50 batch size. Total rows inserted/updated till now: "+ count);
         session.getTransaction().commit();
         session.flush(); session.clear();
         sessionEnded =true; 
        }
         else if(count == storeDetailsDTOs.size()){ 
        session.getTransaction().commit();
         session.flush(); 
        session.clear(); 
        } 
        } 
        logger.info("Insertion completed. Total rows inserted/updated: "+ count);
         return true;
         }
        

        【讨论】:

        • 我以前试过这个。一开始,交易仍然保持开放,不知道为什么。我相信这对于类级别的 @Transactional 注释来说是死的。所以 session.getTransaction().begin() 一开始就引起异常。
        猜你喜欢
        • 2013-05-04
        • 2011-04-05
        • 1970-01-01
        • 2013-03-12
        • 2019-09-22
        • 2021-12-04
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多