JPA Criteria API生成SQL异常:substring参数丢失问题排查
问题分析与解决方案
问题本质
你的Criteria API调用本身没有错误,问题出在Hibernate对substring函数的默认映射上:Hibernate内置的SubstringFunction仅支持两个参数的调用模板(substring(?1, ?2)),而你使用的是三个参数的重载版本(字符串、起始位置、长度),参数数量不匹配导致Hibernate截断了第三个参数,同时抛出HHH000174警告。
另外,你用到的INSTR不属于JPA标准函数,Hibernate默认未正确注册该函数,这也会影响表达式的解析准确性。
修复方案
1. 自定义Hibernate函数映射
在Spring Boot项目中,通过MetadataBuilderContributor同时注册INSTR和支持三个参数的substring函数,确保Hibernate能正确解析你的表达式:
@Slf4j @Configuration public class HibernateConfig { @Bean public HibernatePropertiesCustomizer hibernatePropertiesCustomizer() { return hibernateProperties -> hibernateProperties.put( "hibernate.metadata_builder_contributor", MySQLFunctionsContributor.class.getName() ); } public static class MySQLFunctionsContributor implements MetadataBuilderContributor { @Override public void contribute(MetadataBuilder metadataBuilder) { // 注册INSTR函数,适配MySQL语法 metadataBuilder.applySqlFunction( "instr", new StandardSQLFunction("instr", StandardBasicTypes.INTEGER) ); // 注册支持三个参数的substring函数,匹配你的调用逻辑 metadataBuilder.applySqlFunction( "substring", new StandardSQLFunction( "substring", StandardBasicTypes.STRING, new TemplateRenderer("substring(?1, ?2, ?3)") ) ); } } }
2. 保留原有Criteria代码
你的Criteria查询逻辑无需修改,原代码可以正常工作:
final Path<String> manifestUrlPath = JpaUtils.getPath(SystemComponentTask::getManifestUrl, root); final Expression<Integer> indexExp = cb.diff( cb.function("INSTR", Integer.class, manifestUrlPath, cb.literal("?")), 14 ); cb.substring(manifestUrlPath, indexExp, cb.literal(10));
补充说明
- JPA规范定义了
substring的两种重载形式,但Hibernate默认实现未完全适配所有数据库的多参数语法,需要手动注册对应模板。 - 注册函数时,模板中的参数占位符(
?1、?2、?3)数量必须与你调用时的参数数量一致,否则会再次出现参数不匹配的警告。
内容的提问来源于stack exchange,提问作者Acech
相关产品推荐
相关产品推荐

