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]
4 réponses
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 !!.
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;
}
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
}
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.
De nouvelles questions
java
Java est un langage de programmation de haut niveau. Utilisez cette balise lorsque vous rencontrez des problèmes pour utiliser ou comprendre la langue elle-même. Cette balise est rarement utilisée seule et est le plus souvent utilisée en conjonction avec [spring], [spring-boot], [jakarta-ee], [android], [javafx], [hadoop], [gradle] et [maven].