• java.lang.StackOverflowError解决


    在使用JPA的仓储repository进行查询时,经常用到findAllbyId的方法: repository.findAllbyId()

    但如果像下面的代码,当list的size量太大的话,就会报栈溢出的的错误:java.lang.StackOverflowError

    @RequestMapping("/stackOverFlow")
        public Integer stackOverFlow() {
    
            List<String> ids = new ArrayList<>();
            for (int i = 0; i < 5000; i++) {
                ids.add("123123123123");
            }
            List<BillDO> allById = dwBillRepository.findAllById(ids);
    
            return allById.size();
        }

    报错信息如下:

    Caused by: java.lang.StackOverflowError
        at antlr.BaseAST.toString(BaseAST.java:333) ~[antlr-2.7.7.jar:?]
        at antlr.BaseAST.toStringList(BaseAST.java:341) ~[antlr-2.7.7.jar:?]
        at antlr.BaseAST.toStringList(BaseAST.java:347) ~[antlr-2.7.7.jar:?]
        at antlr.BaseAST.toStringList(BaseAST.java:347) ~[antlr-2.7.7.jar:?]
        at antlr.BaseAST.toStringList(BaseAST.java:347) ~[antlr-2.7.7.jar:?]
        at antlr.BaseAST.toStringList(BaseAST.java:347) ~[antlr-2.7.7.jar:?]
        at antlr.BaseAST.toStringList(BaseAST.java:347) ~[antlr-2.7.7.jar:?]
        at antlr.BaseAST.toStringList(BaseAST.java:347) ~[antlr-2.7.7.jar:?]
        at antlr.BaseAST.toStringList(BaseAST.java:347) ~[antlr-2.7.7.jar:?]
        at antlr.BaseAST.toStringList(BaseAST.java:347) ~[antlr-2.7.7.jar:?]
        at antlr.BaseAST.toStringList(BaseAST.java:347) ~[antlr-2.7.7.jar:?]

    原因就是在拼sql时方法入栈太深,超过了jvm允许的最大深度,也就是递归调用的太深了。

    public String toStringList() {
            String var2 = "";
            if (this.getFirstChild() != null) {
                var2 = var2 + " (";
            }
    
            var2 = var2 + " " + this.toString();
            if (this.getFirstChild() != null) {
                var2 = var2 + ((BaseAST)this.getFirstChild()).toStringList();
            }
    
            if (this.getFirstChild() != null) {
                var2 = var2 + " )";
            }
    
            if (this.getNextSibling() != null) {
                var2 = var2 + ((BaseAST)this.getNextSibling()).toStringList();
            }
    
            return var2;
        }

    解决方法就是不要递归的太深。或者调整JVM参数栈大小默认为1m,可以调整到10m,看看不能解决问题,但这样做不推荐。会影响线程数,从而影响系统性能。

    具体到上面的问题就是一次不要查太多的数据。如果in的数量有5000,我们就分开查询一次只查1000,查5次。再把结果组合在一起。

    如果每个业务都单独写的话,就太麻烦了,可以写个公共的方法,如下: JPA_QUERY_LIST_MAX_SIZE是一个常量数据值,如1000个查一次。这里使用了并行查询,查询效率更高。

    public <T> List<T> findAll(List<String> ids, Function<List<String>, List<T>> func) {
    
            List<List<String>> idGroups = Lists.partition(ids, JPA_QUERY_LIST_MAX_SIZE);
            ThreadPoolExecutor executor = (ThreadPoolExecutor) Executors.newFixedThreadPool(idGroups.size());
    executor.setKeepAliveTime(10, TimeUnit.SECONDS);//解决线程不退出的问题
    executor.allowCoreThreadTimeOut(true);


    return idGroups .stream() .collect(ParallelCollectors .parallelToList(i -> func.apply(i), executor, idGroups.size())) .join() .stream() .flatMap(Collection::stream) .collect(toList()); }

    以上代码利用如一个第三方的库:需要引用:

    <dependency>
                <groupId>com.pivovarit</groupId>
                <artifactId>parallel-collectors</artifactId>
                <version>1.1.0</version>
            </dependency>

    这里引出一个题外话,如果in查询数据量很大的话,可能会导致索引失效的问题。需要重点看一下。

  • 相关阅读:
    利用FormData对象实现AJAX文件上传功能及后端实现
    $.ajax not function(已 解决:jQuery库冲突解决办法)
    什么是docx,pptx等的正确MIME类型?
    session_end
    cookies.Expires (小技巧)
    如何生成静态页面的五种方案(转)
    Request.UserHostAddress和Request.Url.Host(小技巧)
    单点登录的一些实现
    框架页的session和cookies
    在IHttpHandler使用session
  • 原文地址:https://www.cnblogs.com/hankuikui/p/11775394.html
Copyright © 2020-2023  润新知