You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用CriteriaBuilder结合Hibernate StatelessSession构建查询时字符串参数占位符未正确替换的问题求助

解决StatelessSession中HQL参数未正确替换的问题

首先,问题的核心原因在于:scrollQuery.getQueryString()返回的是带有占位符的原始HQL,Hibernate不会自动将绑定的参数值替换到HQL字符串中——你看到Integer参数被替换的情况,大概率是因为这些Integer是常量值(比如枚举的getValue()结果、固定数值),Hibernate在生成HQL时直接将常量嵌入,而String类型的变量参数则会保留占位符(:paramN)。

StatelessSession虽然要求createQuery传入String类型的HQL,但它同样支持参数绑定,不需要手动替换HQL中的占位符(反而手动替换会带来SQL注入风险)。下面是两种可靠的解决方案:

方案一:从原Query提取参数并绑定到StatelessSession的Query

直接从你已经构建好的scrollQuery中提取所有参数的名称和值,然后逐个绑定到StatelessSession创建的Query上:

StatelessSession session = ((Session) EntityManager.getDelegate()).getSessionFactory().openStatelessSession();
// ... 你的Criteria构建代码保持不变 ...
TypedQuery<Concepts> query = EntityManager.createQuery(queryConcepts);
org.hibernate.Query scrollQuery = query.unwrap(org.hibernate.Query.class);

// 创建StatelessSession的Query
org.hibernate.Query statelessQuery = session.createQuery(scrollQuery.getQueryString())
        .setReadOnly(true)
        .setFetchSize(maxCachedRecords)
        .setCacheable(false);

// 提取并绑定所有参数
ParameterMetadata paramMetadata = scrollQuery.getParameterMetadata();
for (Parameter<?> param : paramMetadata.getParameters()) {
    if (param.getName() != null) {
        // 绑定命名参数
        statelessQuery.setParameter(param.getName(), scrollQuery.getParameterValue(param));
    } else {
        // 绑定位置参数(如果有的话)
        statelessQuery.setParameter(param.getPosition(), scrollQuery.getParameterValue(param));
    }
}

// 执行scroll
ScrollableResults scrollconcepts = statelessQuery.scroll(ScrollMode.FORWARD_ONLY);

这种方式完全复用了你原本绑定的参数,既避免了手动拼接HQL的风险,又能保证所有类型的参数(String、Integer等)都能正确传递。

方案二:直接使用StatelessSession的API构建查询(可选)

如果你愿意重构部分代码,可以直接用StatelessSession的HQL字符串来构建查询,同时手动绑定参数:

StatelessSession session = ((Session) EntityManager.getDelegate()).getSessionFactory().openStatelessSession();

String hql = "SELECT a FROM Concepts a, ExportTemp b " +
             "WHERE a.xptoName = b.xptoName " +
             "AND b.keyName = :key " +
             "AND b.id = :exportId";

ScrollableResults scrollconcepts = session.createQuery(hql)
        .setReadOnly(true)
        .setFetchSize(maxCachedRecords)
        .setCacheable(false)
        .setParameter("key", ExportTmpType.CONCEPTS.getValue())
        .setParameter("exportId", tecAccountingExport.getId())
        .scroll(ScrollMode.FORWARD_ONLY);

这种方式更直接,但需要你手动编写HQL,适合逻辑不太复杂的查询场景。

关键提醒

永远不要手动将参数值拼接到HQL字符串中(比如用字符串替换:param1),这会导致SQL注入漏洞。参数绑定是Hibernate提供的安全且可靠的参数传递方式,无论使用Stateful还是StatelessSession都应该优先使用。

内容的提问来源于stack exchange,提问作者Hugo Marinho

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.28 23:24:08