2015-04-15 50 views
3

我有一個問題,使用deleteInBatch從db中刪除項目。 我有一個對象的具有類似對象B的列表:Spring JPA deleteInBatch導致StackOverflow

class A { 
private List <B>; 
} 

該列表包含比7K元素的更多。 所以現在我必須刪除A及其所有元素。我通過deleteInBatch嘗試,但我得到

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

刪除了sipmle刪除方法工作的項目,但它需要超過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並不需要所有的Hibernate棧 - 不增加嗎?

完整的堆棧跟蹤:

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) 

等等....

+0

你可以發佈完整的堆棧跟蹤嗎? –

回答

4
你的情況

,刪除查詢將被翻譯JpaRepository看起來像這樣。

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

JVM發出一個堆棧溢出錯誤,因爲HqlSqlBaseWalker試圖搜索所有(或基本where標準)聲明

我猜,你的情況,你可以嘗試生成您自己的刪除查詢,然後執行它,或者您可以嘗試將數據拆分成少數列表。

+0

所以,你的意思是「批處理」並不真的在內部創建一個JDBC批處理語句?對於任何正在調整光標緩存的DBA來說,這都是一個壞消息... –

+1

@LukasEder嗯,我認爲問題在於這裏的「批處理」術語本身。我的意思是,我們通常在這種情況下期望的是,hibernate將分割數據並嘗試插入這些數據,例如對每100個數據進行一次查詢。但是,如果您閱讀api文檔,它確實提到該函數確實會創建一個「查詢」。所以,我認爲這裏的教訓是我們應該三思而後行,來命名我們的公共api;) –

+0

是的,我創建了我自己的刪除查詢。這個過程花了3分鐘,但我創建了一個關鍵的索引,它的效果很好。謝謝 :) – kamirru

0

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

相關問題