How can we call a stored procedure with Hibernate and JPA?

后端 未结 7 1363
时光取名叫无心
时光取名叫无心 2020-12-15 06:34

How can we call a stored procedure using Hibernate or JPA?

相关标签:
7条回答
  • 2020-12-15 07:13

    To execute remote procedure use this construction:

    Mapping

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

    Java code

    session.getNamedQuery("RP").setInteger("param1", 1).setInteger("param2", 2).executeUpdate();
    
    0 讨论(0)
  • 2020-12-15 07:15

    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

    0 讨论(0)
  • 2020-12-15 07:20

    Hibernate provides support for queries via stored procedures and functions. Say for example if we have the following stored procedure,

    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;
    

    Which return the list of all employees. The stored procedure/function must return a resultset as the first out-parameter to be able to work with Hibernate.

    To use the above query in Hibernate you need to map it via a named query.

    <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>
    

    Rules/limitations for using stored procedures:

    • Stored procedure queries cannot be paged with setFirstResult()/setMaxResults().
    • The recommended call form is standard SQL92: { ? = call functionName(<parameters>) } or { ? = call procedureName(<parameters>}. Native call syntax is not supported.

    For Oracle the following rules apply:

    • A function must return a result set.
    • The first parameter of a procedure must be an OUT that returns a result set. This is done by using a SYS_REFCURSOR type in Oracle 9 or 10. In Oracle you need to define a REF CURSOR type. See Oracle literature for further information.

    For Sybase or MS SQL server the following rules apply:

    • The procedure must return a result set. Note that since these servers can return multiple result sets and update counts, Hibernate will iterate the results and take the first result that is a result set as its return value. Everything else will be discarded.
    • If you can enable SET NOCOUNT ON in your procedure it will probably be more efficient, but this is not a requirement.

    Source Ref.: From the official Hibernate docuementation.

    0 讨论(0)
  • 2020-12-15 07:23

    Considering the following stored procedure that simply returns a basic return value:

    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;
    

    You can call this one with standard 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);
    

    If the stored procedure returns a 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;
    

    You can call it like this:

    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();
    

    If you want to call an Oracle database function:

    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;
    

    You can't use the StoredProcedureQuery since it does not work with Hibernate 5, so you can call it like this:

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

    or with plain 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 );
        }
    } );
    

    For more details check out the following articles:

    • How to call Oracle stored procedures and functions with JPA and Hibernate
    • How to call SQL Server stored procedures and functions with JPA and Hibernate
    • How to call PostgreSQL functions (stored procedures) with JPA and Hibernate
    • How to call MySQL stored procedures and functions with JPA and Hibernate
    0 讨论(0)
  • 2020-12-15 07:29

    Here is the complete Solution to call a Stored Procedure with Just IN parameters ---

    1) Create the Stored Procedure to act on a Table or a Set of Tables:

    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) Execute the Stored Procedure from SQL Prompt to check the input. When You call the procedure from Java/Hibernate also You should see the similar result:

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

    3) In the Java Code:

    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) Now check the result in the Table, that should get updated accordingly:

    0 讨论(0)
  • 2020-12-15 07:29

    one approach can be 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());
    }
    

    you have to map or use annotations

    there are others: source

    0 讨论(0)
提交回复
热议问题