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

如何在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.

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.03 05:15:04