Java静态常量拼接SQL IN子句本地正常Jenkins报StackOverflowError原因
错误原因
该报错属于编译期栈溢出,而非代码运行时错误,触发原因有两个:
- 你给B类的
query字段加了static final修饰,javac编译器在编译阶段会尝试对静态常量的赋值表达式做常量折叠优化,而你这里的表达式用到了Stream + Lambda的复杂链式调用,部分旧版本javac在处理这类复杂的静态常量初始化表达式的类型推导、常量折叠逻辑时存在已知的栈溢出Bug。 - 你的本地开发环境和Jenkins构建环境的配置不一致:要么是Jenkins使用的JDK版本刚好命中上述Bug,要么是Jenkins编译任务给JVM设置的栈内存(
-Xss参数)远小于本地环境,扛不住javac处理这段逻辑的栈消耗。
解决方案
你可以任选以下一种方式修复:
- 把静态常量的初始化逻辑移到静态代码块中,避免javac尝试做常量折叠优化:
public class B { public static final String query; static { query = "SELECT NAME FROM TABLE WHERE STATE IN " + A.getValues().stream() .map(key -> "'" + key + "'") .collect(Collectors.joining(",", "(", ")")); } }
- 调整Jenkins编译任务的JVM参数,调大栈内存,比如给javac启动参数加上
-Xss1m(可根据实际情况调整大小),同时将Jenkins使用的JDK版本升级到和本地环境一致的较新版本,避开javac的已知Bug。 - 不用Stream拼接,改用普通for循环拼接字符串,降低javac编译时的栈消耗。
注意:直接拼接SQL字符串存在SQL注入风险,如果Set的值为用户可控制的输入,一定要做特殊字符转义,或者改用预编译SQL处理IN参数。
内容的提问来源于stack exchange,提问作者Sarthak
相关产品推荐
相关产品推荐

