[英]How can we call a stored procedure with Hibernate and JPA?
我們如何使用 Hibernate 或 JPA 調用存儲過程?
考慮以下僅返回基本返回值的存儲過程:
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 );
}
} );
有關更多詳細信息,請查看以下文章:
您可以執行以下操作
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();
請在需要的地方添加異常處理。
從休眠中調用存儲過程的一種方法
在@NamedNativeQueries
注釋中聲明您的存儲過程
//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());
}
這有效
要執行遠程過程,請使用以下結構:
映射
<sql-query name="RP">
{call some_rp(:param1, :param2)}
</sql-query>
Java代碼
session.getNamedQuery("RP").setInteger("param1", 1).setInteger("param2", 2).executeUpdate();
這是使用 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 Prompt 執行存儲過程以檢查輸入。 當您從 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。
要在 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 functionName(<parameters>) }
或{ ? = call procedureName(<parameters>}
{ ? = call procedureName(<parameters>}
。不支持本機調用語法。 For Oracle the following rules apply:
For Sybase or MS SQL server the following rules apply:
一種方法是使用 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());
}
您必須映射或使用注釋
還有其他: 來源
這種調用過程的簡單而聰明的方法:
@Query(value = "call SCHEMA.PROCEDURE_NAME()" , nativeQuery = true)
如果您的過程包含參數,您可以像下面這樣調用它:
@Transactional
@Modifying
@Query(value = "call SCHEMA.PROCEDURE_NAME(:param1 , :param2)" , nativeQuery = true)
void validateUpdatePaymentStatus(@Param("param1") String param1, @Param("param2") int param2);
如果您的過程包含更新、插入或刪除使用
@Transactional
@Modifying
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.