我们如何使用Hibernate或JPA调用存储过程?
答案 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>
使用存储过程的规则/限制:
{ ? = call functionName(<parameters>) }
或{ ? = call procedureName(<parameters>}
。不支持本机调用语法。 For Oracle the following rules apply:
For Sybase or MS SQL server the following rules apply:
答案 7 :(得分:0)
一种方法可以使用getNamedQuery()。
../../third_party/llvm-build/Release+Asserts/bin/clang++: 1:
../../third_party/llvm-build/Release+Asserts/bin/clang++:
Syntax error: "(" unexpected
您必须映射或使用注释
还有其他人:source