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

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

您可以执行以下操作

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

请在需要时添加exception处理。

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

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

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

  • 如何使用JPA和Hibernate调用Oracle存储过程和函数
  • 如何使用JPA和Hibernate调用SQL Server存储过程和函数
  • 如何使用JPA和Hibernate调用PostgreSQL函数(存储过程)
  • 如何使用JPA和Hibernate调用MySQL存储过程和函数

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

制图

  {call some_rp(:param1, :param2)}  

Java代码

 session.getNamedQuery("RP").setInteger("param1", 1).setInteger("param2", 2).executeUpdate(); 
 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 

你应该去官方的hibernate文档站点。 无论如何这里是直接带你到存储过程部分的链接

以下是使用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)现在检查表中的结果,该结果应相应更新:

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中使用上述查询,您需要通过命名查询映射它。

              { ? = call selectAllEmployments() }  

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

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

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,那么它可能会更有效,但这不是必需的。

来源参考:来自官方的Hibernate docuementation。

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

 Query query = session.getNamedQuery("callStockStoreProcedure") .setParameter("stockCode", "7277"); List result = query.list(); for(int i=0; i 

你必须映射或使用注释

还有其他: 来源