升级Hibernate 5.3后IN子句多参数引发StackOverflowError求助
解决Hibernate 5.3多参数IN子句引发StackOverflowError的方案
这个栈溢出问题是Hibernate 5.3版本中StringHelper.replace方法的递归实现缺陷导致的——当查询包含多个带大量参数的IN子句时,递归替换字符串的调用深度超过了JVM栈的限制。以下是针对Spring Boot 2.7.18 + Hibernate 5.3.x环境的可行解决办法:
升级到Hibernate 5.3最新补丁版本
Hibernate 5.3的后续小版本(如5.3.30.Final及以上)已经修复了该递归栈溢出问题。Spring Boot 2.7.x默认依赖的Hibernate版本可能不是最新补丁版,你可以手动在依赖管理中指定最新的5.3.x版本:
Maven配置示例:<dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-core</artifactId> <version>5.3.30.Final</version> </dependency>Gradle配置示例:
implementation 'org.hibernate:hibernate-core:5.3.30.Final'拆分大IN子句
如果暂时无法升级补丁,可将单个包含大量参数的IN子句拆分为多个小IN子句,通过OR连接。例如把WHERE id IN (:largeIdList)拆成WHERE id IN (:idList1) OR id IN (:idList2),减少单次字符串替换的处理长度,避免递归栈溢出。同时注意控制每个IN子句的参数数量(参考对应数据库的参数上限,比如MySQL默认建议不超过1000)。替换StringHelper的递归实现(临时应急方案)
自定义一个非递归的org.hibernate.internal.util.StringHelper类覆盖Hibernate原类:- 复制原
StringHelper代码,将replace方法改为迭代实现:
public static String replace(String template, String placeholder, String replacement) { if (template == null) { return null; } int startIndex = template.indexOf(placeholder); if (startIndex == -1) { return template; } StringBuilder result = new StringBuilder(template.length() + replacement.length() * 10); int lastPosition = 0; while (startIndex != -1) { result.append(template, lastPosition, startIndex); result.append(replacement); lastPosition = startIndex + placeholder.length(); startIndex = template.indexOf(placeholder, lastPosition); } result.append(template.substring(lastPosition)); return result.toString(); }- 通过类加载机制让自定义类优先加载(比如放在项目的
src/main/java/org/hibernate/internal/util目录下),但这种方式存在兼容性风险,仅作为临时过渡方案。
- 复制原
内容的提问来源于stack exchange,提问作者Abdel
相关产品推荐
相关产品推荐

