Criteria API抛出StackOverflowException的原因排查
问题分析与解决方案
这个栈溢出问题的核心是Hibernate在处理双向一对一关联的Criteria查询时,元数据解析环节出现了无限递归调用——从异常栈可以看到,AbstractSqmAttributeJoin.getNodeJavaTypeDescriptor和SqmSingularJoin.getJavaTypeDescriptor方法一直在互相调用,直到栈内存耗尽。
为什么会触发这个问题?
你的实体类双向一对一关联配置本身是正确的(Customer作为拥有方,Cart用mappedBy维护反向关联),但当你用Criteria API从Customer作为Root来关联Cart时,Hibernate在解析这个join节点的类型信息时,因为双向引用的元数据处理逻辑出现了循环,导致无限递归。
解决方案
1. 调整Criteria查询的写法(最直接的解决方法)
换个思路,从Cart作为查询Root,关联Customer来构建查询,避开触发循环的逻辑:
CriteriaBuilder cb = entityManager.getCriteriaBuilder(); CriteriaQuery<Cart> query = cb.createQuery(Cart.class); // 从Cart作为Root节点 Root<Cart> cartRoot = query.from(Cart.class); // 关联Customer Join<Cart, Customer> customerJoin = cartRoot.join("customer"); // 使用参数表达式绑定参数(修正了你之前的拼写错误和未使用的问题) ParameterExpression<String> usernameParam = cb.parameter(String.class); query.select(cartRoot) .where(cb.equal(customerJoin.get("username"), usernameParam)); // 执行查询 Cart cart = entityManager.createQuery(query) .setParameter(usernameParam, name) .getSingleResult(); return cart;
2. 修复代码中的其他小问题
- 你定义的
ParameterExpression拼写错误(strignParameter→stringParameter),而且之前没有实际使用它,建议用参数表达式绑定参数,这是Criteria API的规范用法,也能避免SQL注入风险。 Customer类的toString方法里拼写错误:Costumer→Customer(虽然这不是栈溢出的原因,但建议修正)。
3. 升级Hibernate版本
如果你的Hibernate版本比较旧,这种元数据解析的循环调用bug可能已经在新版本中被修复了,建议升级到最新的稳定版(比如5.6.x或6.x系列)。
内容的提问来源于stack exchange,提问作者Dolphy the Reaper
相关产品推荐
相关产品推荐

