Hibernate 5迁移至Hibernate 6时,自定义函数SINGLE_COLUMN_FROM_JSON_TABLE在H2方言中的适配错误问题
Hibernate 5迁移至Hibernate 6时,自定义函数SINGLE_COLUMN_FROM_JSON_TABLE在H2方言中的适配错误问题
我太懂你这种迁移时踩细节坑的痛苦了!Hibernate 6对自定义函数的处理逻辑确实和5有不少差异,尤其是你遇到的这个场景——H2里多出来的那层双层括号((?, ?, ?))直接让H2把参数当成了ROW类型,自然就报数据转换错误了。咱们一步步来解决这个问题:
问题核心复盘
你的自定义函数SINGLE_COLUMN_FROM_JSON_TABLE在Oracle里能正常转成json_table子查询,完全没问题;但在H2里你希望它直接展开成参数列表(?, ?, ?),结果Hibernate 6硬给套了一层额外的括号,导致SQL语法逻辑出错。
解决方案尝试
1. 调整H2方言中自定义函数的注册逻辑
Hibernate 6对函数的返回类型、参数解析逻辑更严谨,你需要明确告诉Hibernate:这个函数在H2里返回的是值列表,不需要额外包裹括号。可以通过自定义SQLFunction实现来控制SQL渲染:
public class CustomH2Dialect extends H2Dialect { public CustomH2Dialect() { super(); addSqlFunction("SINGLE_COLUMN_FROM_JSON_TABLE", new SQLFunction() { @Override public boolean hasArguments() { return true; } @Override public boolean hasParenthesesIfNoArguments() { return false; } @Override public Type getReturnType(Type firstArgumentType, Mapping mapping) throws QueryException { // 匹配你的ID字段类型,比如Long return StandardBasicTypes.LONG; } @Override public String render(Type firstArgumentType, List<?> args, SessionFactoryImplementor factory) throws QueryException { // 直接生成逗号分隔的占位符,不包裹函数名和外层括号 if (args.isEmpty()) { return "()"; } // 假设传入的是集合参数,按元素数量生成占位符 Collection<?> paramCollection = (Collection<?>) args.get(0); StringBuilder placeholderSb = new StringBuilder(); for (int i = 0; i < paramCollection.size(); i++) { if (i > 0) { placeholderSb.append(","); } placeholderSb.append("?"); } return placeholderSb.toString(); } }); } }
2. 验证函数渲染行为
注册完自定义方言后,记得开启Hibernate的SQL日志(设置hibernate.show_sql=true),观察生成的SQL是否变成:
select t from TestTable t WHERE t.id IN ( ?,?,? )
如果还是有双层括号,那可能是Hibernate对IN子句中函数调用的默认处理逻辑导致的,这时候可以再加一步:
3. 用SQL拦截器修正生成的SQL
如果上面的方法没生效,咱们可以用Hibernate的StatementInspector来拦截生成的SQL,手动去掉多余的括号:
public class H2SqlFixInspector implements StatementInspector { @Override public String inspect(String sql) { // 针对H2数据库,替换掉IN后的双层括号 if (sql.contains("IN (( ?")) { return sql.replace("IN (( ", "IN ( ").replace("))", ")"); } return sql; } }
然后在Hibernate配置里启用这个拦截器:
hibernate.session_factory.statement_inspector=com.yourpackage.H2SqlFixInspector
额外注意点
- 确保你的H2版本和Hibernate 6兼容,建议用H2 2.x的最新稳定版,避免版本不匹配带来的隐性问题;
- 测试时要单独针对H2环境跑,确认参数绑定和SQL生成都符合预期;
- Hibernate 6里集合参数的处理逻辑和5不同,如果你是直接传集合作为函数参数,要确保参数绑定正确。
备注:内容来源于stack exchange,提问作者Bartun
相关产品推荐
相关产品推荐

