hibernate 使用@Procedure从java spring Boot 调用带类型参数的存储过程

mzsu5hc0  于 8个月前  发布在  Java
关注(0)|答案(1)|浏览(110)

我已经开发了一个存储过程来在DB中执行一些任务,它获取一个自定义类型参数。

DROP TYPE IF EXISTS custom_type CASCADE;
CREATE TYPE custom_type AS (
    field1 integer,
    field2 integer
);

CREATE OR REPLACE PROCEDURE my_proc(param1 custom_type) AS $$
BEGIN
    -- DO NOTHING FOR NOW
END;
$$ LANGUAGE 'plpgsql';

在我的java代码中,我已经创建了这个自定义类型作为一个类,并添加了连接到我的存储库中的过程,如下所示。

@Data
public class CustomType {
    int field1;
    int field2;
    public CustomType(Integer field1, Integer field2) {
        this.field1 = field1;
        this.field2 = field2;
    }
}
public interface MyRepo extends RdbFilterQueryRepository<MyEntity> {

   @Procedure(value = "my_proc")
   void myProc(@Param("param1") CustomType myParam1);

}

当我调用这个过程时,我得到这个错误:Caused by: java.lang.IllegalArgumentException: Cannot determine the bindable type for procedure parameter: null
我试过很多方法,但都不管用。我已经改变了自定义类型为一个简单的整数,它的作品..我理解它连接到参数类型,并在DB中的类型与我的类类型之间绑定。但我找不到办法。我错过了什么?

  • 更新-
    通过将UserType<T>实现为一个类型转换器,并通过TypeContributor的另一个组件实现注册它,我已经设法使它与一个简单的自定义类型(包含单个字段)一起工作。
    在我们的例子中,自定义类型有多个字段。所以我尝试实现类型转换器CompositeUserType<T>,但遗憾的是我没有设法注册它,因为TypeContributor register函数只能得到UserType<T>
    我已经在hibernate中创建了一个ticket。他们建议使用@CompositeTypeRegistration的解决方案,但它并不起作用。
nqwrtyyt

nqwrtyyt1#

最后找到了一种方法让它工作。它不是最佳的,但它工作。
我们的java类型-相当于我们的postgres类型custom_type(在我的帖子中查看DB声明)

public record MyType(int field1, int field2) {
        @Override
        public String toString() {
            return "(" + field1 + "," + field2 + ")";
        }
    }

声明转换器类型

class MyUserType implements UserType<MyType> {
    ...

    public static final MyUserType INSTANCE = new MyUserType();

    @Override
    public void nullSafeSet(PreparedStatement st, MyType value, int index, 
    SharedSessionContractImplementor session) throws SQLException {
        st.setString(index, value.toString());
    }

    ...
}

注册我们的自定义类型

public class MyUserTypesContributor implements TypeContributor {

    public MyUserTypesContributor () {
    }

    @Override
    public void contribute(TypeContributions typeContributions, ServiceRegistry serviceRegistry) {
        typeContributions.contributeType(MyUserType.INSTANCE);
    }
}

创建文件./resources/META-INF.services/org.hibernate.boot.model.TypeContributor文件的内容将是该类型贡献者的完整包

com......hibernate.types.MyUserTypesContributor

这样我们的类型贡献器将被Hibernate加载,并且我们的类型将被注册
存储库中

public interface MyRepository extends RdbFilterQueryRepository<...> {
    ...

    @Procedure("my_procedure")
    @Transactional
    @Modifying
    void myProc(@Param("param1")  MyType val);
     
    ...
}

剩下要做的就是调用我们的过程

myRepo.myProc(new MyType(123,345));

相关问题