简体   繁体   中英

Spring JPA deleteInBatch causes StackOverflow

I have a question to deleting Items from db using deleteInBatch. I have an object A having a list of Objects B like:

class A {
private List <B>;
}

The list contains more than 7k elements. So now I have to remove A and all its elements. I tried via deleteInBatch but I get

org.springframework.web.util.NestedServletException: Handler processing failed;
nested exception is java.lang.StackOverflowError

Deleting the items with a sipmle delete method works but it takes more than 5 minutes. My delete code is:

public void delete(Long id) {
A a = repository.findOne(id);
deleteElements(a);
repository.delete(a);
}

private void deleteElements(A a) {
repository.deleteInBatch(a.getListOfB);
}

Is there a good solution to speed up the deleting process or how to change so that deleteinbatch does not take all hibernate stack - without increasing it?

The complete Stacktrace:

org.springframework.web.util.NestedServletException: Handler processing failed; nested exception is java.lang.StackOverflowError
org.springframework.web.servlet.DispatcherServlet.triggerAfterCompletionWithError(DispatcherServlet.java:1259)
org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:945)
org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:856)
org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:936)
org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:827)
javax.servlet.http.HttpServlet.service(HttpServlet.java:620)
org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:812)
javax.servlet.http.HttpServlet.service(HttpServlet.java:727)
org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
net.bull.javamelody.MonitoringFilter.doFilter(MonitoringFilter.java:163)
net.bull.javamelody.MonitoringFilter.doFilter(MonitoringFilter.java:206)
net.bull.javamelody.MonitoringFilter.doFilter(MonitoringFilter.java:179)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:118)
org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:84)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:113)

And so on...

root cause

java.lang.StackOverflowError
org.hibernate.hql.internal.ast.tree.SqlNode.<init>(SqlNode.java:34)
sun.reflect.GeneratedConstructorAccessor36.newInstance(Unknown Source)
sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
java.lang.reflect.Constructor.newInstance(Constructor.java:526)
java.lang.Class.newInstance(Class.java:379)
org.hibernate.hql.internal.ast.SqlASTFactory.create(SqlASTFactory.java:256)
antlr.ASTFactory.create(ASTFactory.java:153)
antlr.ASTFactory.create(ASTFactory.java:186)
org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.logicalExpr(HqlSqlBaseWalker.java:2018)
org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.logicalExpr(HqlSqlBaseWalker.java:2026)
org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.logicalExpr(HqlSqlBaseWalker.java:2026)

And so on....

in your case, the delete query will be translated by JpaRepository to be looks like this.

delete from [table_name] where [criteria] = id or [criteria] = id (and so on...)

the jvm throws a stack overflow error because the HqlSqlBaseWalker is trying to search all the or (or basically the where criteria) statement

I guess, in your case, you could try to generate your own delete query and then execute it or you could try to split the data into few lists.

我遇到了同样的问题 (java.lang.StackOverflowError) 并使用我自己的删除查询创建了一个方法,例如 deleteByIdAndYear(...),以避免它。

I ended up combining deleteInBatch with an answer to another question :

import com.google.common.collect.Lists;
...
Lists.partition(messages, 500)
        .forEach(fragmentMessageDao::deleteInBatch);

For me, this gave a proper and elegant solution because I already needed the data for another calculation

In my case deleting entities in smaller chunks helped. Chunks of 100 items worked just fine.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM