我们如何使用Hibernate和JPA调用存储过程?

时间:2010-12-24 07:17:07

标签: java database hibernate stored-procedures orm

我们如何使用Hibernate或JPA调用存储过程?

8 个答案:

答案 0 :(得分:13)

考虑以下只返回基本返回值的存储过程:

CREATE OR REPLACE PROCEDURE count_comments (  
   postId IN NUMBER,  
   commentCount OUT NUMBER )  
AS 
BEGIN 
    SELECT COUNT(*) INTO commentCount  
    FROM post_comment  
    WHERE post_id = postId; 
END;

你可以用标准的JPA来称呼它:

StoredProcedureQuery query = entityManager
    .createStoredProcedureQuery("count_comments")
    .registerStoredProcedureParameter(1, Long.class, 
        ParameterMode.IN)
    .registerStoredProcedureParameter(2, Long.class, 
        ParameterMode.OUT)
    .setParameter(1, 1L);

query.execute();

Long commentCount = (Long) query.getOutputParameterValue(2);

如果存储过程返回SYS_REFCURSOR:

CREATE OR REPLACE PROCEDURE post_comments ( 
   postId IN NUMBER, 
   postComments OUT SYS_REFCURSOR ) 
AS 
BEGIN
    OPEN postComments FOR
    SELECT *
    FROM post_comment 
    WHERE post_id = postId; 
END;

您可以这样称呼它:

StoredProcedureQuery query = entityManager
    .createStoredProcedureQuery("post_comments")
    .registerStoredProcedureParameter(1, Long.class, 
         ParameterMode.IN)
    .registerStoredProcedureParameter(2, Class.class, 
         ParameterMode.REF_CURSOR)
    .setParameter(1, 1L);

query.execute();

List<Object[]> postComments = query.getResultList();

如果要调用Oracle数据库函数:

CREATE OR REPLACE FUNCTION fn_count_comments ( 
    postId IN NUMBER ) 
    RETURN NUMBER 
IS
    commentCount NUMBER; 
BEGIN
    SELECT COUNT(*) INTO commentCount 
    FROM post_comment 
    WHERE post_id = postId; 
    RETURN( commentCount ); 
END;

你不能使用StoredProcedureQuery,因为它不适用于Hibernate 5,所以你可以像这样调用它:

BigDecimal commentCount = (BigDecimal) entityManager
    .createNativeQuery(
        "SELECT fn_count_comments(:postId) FROM DUAL"
    )
    .setParameter("postId", 1L)
    .getSingleResult();

或使用普通JDBC:

Session session = entityManager.unwrap( Session.class ); 

Integer commentCount = session.doReturningWork( connection -> {
    try (CallableStatement function = connection.prepareCall(
            "{ ? = call fn_count_comments(?) }" )) {
        function.registerOutParameter( 1, Types.INTEGER );
        function.setInt( 2, 1 );
        function.execute();
        return function.getInt( 1 );
    }
} );

有关详细信息,请查看以下文章:

答案 1 :(得分:2)

您可以执行以下操作

 Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();
PreparedStatement st = session.connection().prepareStatement("{call procedureName(?, ?)}");
                st.setString(1, formatter.format(parameter1));
                st.setString(2, formatter.format(parameter2));
                st.execute();
tx.commit();

请在需要时添加例外处理。

答案 2 :(得分:2)

要执行远程过程,请使用以下结构:

<强>映射

<sql-query name="RP">   
    {call some_rp(:param1, :param2)}
</sql-query>

Java代码

session.getNamedQuery("RP").setInteger("param1", 1).setInteger("param2", 2).executeUpdate();

答案 3 :(得分:1)

One way to call the stored procedure from hibernate 

Declare your store procedure inside the @NamedNativeQueries annotation

//Stock.java

@NamedNativeQueries({
    @NamedNativeQuery(
    name = "callStockStoreProcedure",
    query = "CALL GetStocks(:stockCode)",
    resultClass = Stock.class
    )
})
@Entity
@Table(name = "stock")
public class Stock implements java.io.Serializable {

Call it with getNamedQuery().

Query query = session.getNamedQuery("callStockStoreProcedure")
    .setParameter("stockCode", "7277");
List result = query.list();
for(int i=0; i<result.size(); i++){
    Stock stock = (Stock)result.get(i);
    System.out.println(stock.getStockCode());
}

This works

答案 4 :(得分:0)

你应该去官方的hibernate文档站点。无论如何here is the link将您直接带到存储过程部分

答案 5 :(得分:0)

以下是使用Just IN参数调用存储过程的完整解决方案---

1)创建存储过程以对表或一组表进行操作:

CREATE OR REPLACE procedure insertHouseHello (
house_date in timestamp,
house_name in varchar2,
house_number in number,
house_value in float) 
is
begin
 insert into House("HOUSE_DATE","HOUSE_NAME","HOUSE_NUMBER","HOUSE_VALUE")
 values ( house_date, house_name,house_number,house_value);
 commit;
 end;

2)从SQL提示符执行存储过程以检查输入。当您从Java / Hibernate调用该过程时,您应该看到类似的结果:

exec insertHouseHello(sysdate,'one',123,104); 

3)在Java代码中:

log.info("Now trying to call the Stored Procedure*****************");
Query exQuery = session.createSQLQuery("CALL " +
        "insertHouseHello(:timestmp,:hname,:hno,:hvalue)");
exQuery.setParameter("timestmp", 
        new java.sql.Timestamp(Calendar.getInstance().getTime().getTime()));
exQuery.setParameter("hname", 34);
exQuery.setParameter("hno", 212);
exQuery.setParameter("hvalue", 12);
int exRows = exQuery.executeUpdate();
log.info("Executed Rows from Stored Procedure****************"+exRows);

4)现在检查表中的结果,该结果应相应更新:

答案 6 :(得分:0)

Hibernate通过存储过程和函数为查询提供支持。比如说我们有以下存储过程,

CREATE OR REPLACE FUNCTION selectAllEmployments
RETURN SYS_REFCURSOR
AS
    st_cursor SYS_REFCURSOR;
BEGIN
    OPEN st_cursor FOR
 SELECT EMPLOYEE, EMPLOYER,
 STARTDATE, ENDDATE,
 REGIONCODE, EID, VALUE, CURRENCY
 FROM EMPLOYMENT;
      RETURN  st_cursor;
 END;

返回所有员工的列表。存储过程/函数必须返回一个结果集作为第一个能够使用Hibernate的out参数。

要在Hibernate中使用上述查询,您需要通过命名查询映射它。

<sql-query name="selectAllEmployees_SP" callable="true">
    <return alias="emp" class="Employment">
        <return-property name="employee" column="EMPLOYEE"/>
        <return-property name="employer" column="EMPLOYER"/>
        <return-property name="startDate" column="STARTDATE"/>
        <return-property name="endDate" column="ENDDATE"/>
        <return-property name="regionCode" column="REGIONCODE"/>
        <return-property name="id" column="EID"/>
        <return-property name="salary">
            <return-column name="VALUE"/>
            <return-column name="CURRENCY"/>
        </return-property>
    </return>
    { ? = call selectAllEmployments() }
</sql-query>

使用存储过程的规则/限制:

  • 无法使用setFirstResult()/ setMaxResults()分页存储过程查询。
  • 推荐的致电表格为标准SQL92:{ ? = call functionName(<parameters>) }{ ? = call procedureName(<parameters>}。不支持本机调用语法。

For Oracle the following rules apply:

  • 函数必须返回结果集。
  • 过程的第一个参数必须是返回结果集的OUT。这是通过在Oracle 9或10中使用SYS_REFCURSOR类型来完成的。在Oracle中,您需要定义REF CURSOR类型。有关详细信息,请参阅Oracle文献。

For Sybase or MS SQL server the following rules apply:

  • 该过程必须返回结果集。请注意,由于这些服务器可以返回多个结果集和更新计数,因此Hibernate将迭代结果并将结果集的第一个结果作为其返回值。其他一切都将被丢弃。
  • 如果你可以在你的程序中启用SET NOCOUNT ON,它可能会更有效率,但这不是必需的。

Source Ref.: From the official Hibernate docuementation.

答案 7 :(得分:0)

一种方法可以使用getNamedQuery()。

../../third_party/llvm-build/Release+Asserts/bin/clang++: 1:
../../third_party/llvm-build/Release+Asserts/bin/clang++:
Syntax error: "(" unexpected

您必须映射或使用注释

还有其他人:source