Je suis nouveau dans Hibernate. J'essaie d'écrire une méthode qui insérera ou mettra à jour 50 enregistrements, puis le validera et continuera à nouveau à insérer. Je fais cela parce que si quelque chose s'est produit lors de l'insertion du dernier enregistrement, je veux conserver tous les enregistrements précédents dans la base de données.

Voici ce que je fais:

@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;
    }

Cela fonctionne bien mais après l'exécution de cette méthode, une exception se produit. La valeur de retour de cette méthode n'est jamais retournée à la méthode appelante pour cette raison. Quelqu'un peut-il m'aider? Le stacktrace:

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]
0
Sumit 22 nov. 2017 à 23:04

4 réponses

Meilleure réponse

J'ai mis @Transactional au niveau de la classe. Je pense que cela causait le problème, même si je ne suis pas sûr. Après l'avoir supprimé, j'obtenais une erreur lors de l'exécution: this.hibernateSessionFactory.getCurrentSession();. Je pense que je dois définir une propriété pour cela.

Quoi qu'il en soit pour réaliser ce que je voulais j'ai modifié la méthode:

@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;
    }

J'appelle cette méthode après avoir 50 enregistrements à insérer. Veuillez noter que j'ai conservé l'annotation @Transactional au niveau de la classe après avoir modifié la méthode.

Merci pour l'aide de tous !!.

1
Sumit 24 nov. 2017 à 09:13

Il y a une erreur dans la vérification du drapeau qui empêche la transaction de commencer. J'ai fait les changements en espérant que cela fonctionnera.

@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;
 }
0
sreekumar v 23 nov. 2017 à 15:47

Voici le code dans lequel vous pouvez vider les enregistrements dans la base de données après 50 enregistrements, mais en validant / annulant tout en cas d'échec, ce qui est normalement le scénario, mais si vous souhaitez valider 50 enregistrements, exécutez la validation après effacement.

    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
}
0
Har Krishan 23 nov. 2017 à 15:21

Vous n'ouvrez la session que si sessionEnded est true mais vous ne la définissez sur true qu'après session.getTransaction().commit(). La meilleure solution serait de démarrer et de terminer la session en dehors de la boucle.

1
ps-aux 22 nov. 2017 à 20:12
47443071