我们如何使用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
如果要调用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
你必须映射或使用注释
还有其他: 来源