如何在Hibernate方言中注册支持可变参数的MySQL函数
解决方案
核心思路是自定义实现Hibernate的SQLFunction接口,动态拼接参数占位符,替代固定参数数量的SQLFunctionTemplate。
步骤1:实现可变参数通用函数类
import org.hibernate.QueryException; import org.hibernate.dialect.function.SQLFunction; import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.type.Type; import java.util.List; public class VariableArgsSQLFunction implements SQLFunction { private final Type returnType; private final String functionName; private final int minRequiredArgs; public VariableArgsSQLFunction(Type returnType, String functionName, int minRequiredArgs) { this.returnType = returnType; this.functionName = functionName; this.minRequiredArgs = minRequiredArgs; } @Override public boolean hasArguments() { return true; } @Override public boolean hasParenthesesIfNoArguments() { return true; } @Override public Type getReturnType(Type firstArgumentType, org.hibernate.engine.spi.Mapping mapping) throws QueryException { return returnType; } @Override public String render(Type firstArgumentType, List arguments, SessionFactoryImplementor factory) throws QueryException { // 参数合法性校验 if (arguments.size() < minRequiredArgs) { throw new QueryException( String.format("函数%s最少需要%d个参数,当前仅传入%d个", functionName, minRequiredArgs, arguments.size()) ); } // 动态拼接所有参数 return functionName + "(" + String.join(", ", arguments) + ")"; } }
步骤2:注册JSON_SET函数
在你的方言初始化逻辑中,替换原有SQLFunctionTemplate的注册方式:
// 第三个参数3表示JSON_SET最少需要3个入参(json文档、第一个path、第一个val) registerFunction("JSON_SET", new VariableArgsSQLFunction(StringType.INSTANCE, "JSON_SET", 3));
步骤3:使用示例
HQL中可以直接传入任意数量的path/val组合,框架会自动拼接成合法的SQL:
// 示例:同时修改两个路径的值,共传入5个参数 Query query = session.createQuery( "SELECT JSON_SET(content, '$.title', :title, '$.status', :status) FROM Article WHERE id = :id" ); query.setParameter("title", "新标题"); query.setParameter("status", 1); query.setParameter("id", 1001);
Hibernate 6+ 简化方案
如果你使用Hibernate 6及以上版本,无需自定义实现类,直接通过MetadataBuilderContributor注册即可:
public class SqlFunctionsContributor implements MetadataBuilderContributor { @Override public void contribute(MetadataBuilder metadataBuilder) { metadataBuilder.applySqlFunction( "JSON_SET", new org.hibernate.dialect.function.StandardSQLFunction( "JSON_SET", StringType.INSTANCE, true // 标记为可变参数 ) ); } }
内容的提问来源于stack exchange,提问作者Josh M.
相关产品推荐
相关产品推荐

