簡體   English   中英

Spring JPA deleteInBatch 導致 StackOverflow

[英]Spring JPA deleteInBatch causes StackOverflow

我有一個關於使用 deleteInBatch 從數據庫中刪除項目的問題。 我有一個對象 A 有一個對象 B 的列表,例如:

class A {
private List <B>;
}

該列表包含超過 7k 個元素。 所以現在我必須刪除 A 及其所有元素。 我嘗試通過 deleteInBatch 但我得到

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

使用 sipmle delete 方法刪除項目有效,但需要 5 分鍾以上。 我的刪除代碼是:

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

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

是否有一個很好的解決方案來加速刪除過程或如何更改以便 deleteinbatch 不會占用所有休眠堆棧 - 而不增加它?

完整的堆棧跟蹤:

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)

等等...

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)

等等....

在您的情況下,刪除查詢將由JpaRepository轉換為如下所示。

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

jvm 拋出堆棧溢出錯誤,因為HqlSqlBaseWalker正在嘗試搜索所有(或基本上是where條件)語句

我想,在您的情況下,您可以嘗試生成自己的刪除查詢然后執行它,或者您可以嘗試將數據拆分為幾個列表。

我遇到了同樣的問題 (java.lang.StackOverflowError) 並使用我自己的刪除查詢創建了一個方法,例如 deleteByIdAndYear(...),以避免它。

我最終將deleteInBatch另一個問題的答案結合起來:

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

對我來說,這提供了一個適當而優雅的解決方案,因為我已經需要數據進行另一次計算

在我的情況下,以較小的塊刪除實體有幫助。 100 個項目的大塊工作得很好。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM