Java 如何使用Hibernate和JPA调用存储过程?
如何使用Hibernate或JPA调用存储过程?您可以执行以下操作Java 如何使用Hibernate和JPA调用存储过程?,java,database,hibernate,stored-procedures,orm,Java,Database,Hibernate,Stored Procedures,Orm,如何使用Hibernate或JPA调用存储过程?您可以执行以下操作 Session session = sessionFactory.openSession(); Transaction tx = session.beginTransaction(); PreparedStatement st = session.connection().prepareStatement("{call procedureName(?, ?)}"); st.setString(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();
请根据需要添加异常处理 要执行远程过程,请使用以下结构: 映射
<sql-query name="RP">
{call some_rp(:param1, :param2)}
</sql-query>
下面是使用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;
返回所有员工的列表。存储过程/函数必须返回一个resultset作为first out参数才能使用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>
{?=调用selectAllEmployments()}
使用存储过程的规则/限制:
- 无法使用setFirstResult()/setMaxResults()对存储过程查询进行分页
- 建议的调用形式为标准SQL92:
或{?=call functionName()}
),不支持本机调用语法{?=call procedureName(}
对于Oracle,以下规则适用:
- 函数必须返回结果集
- 过程的第一个参数必须是返回结果集的OUT。这可以通过在Oracle 9或10中使用SYS_REFCURSOR类型来完成。在Oracle中,您需要定义REF CURSOR类型。有关详细信息,请参阅Oracle文献
对于Sybase或MS SQL server,以下规则适用:
- 该过程必须返回一个结果集。请注意,由于这些服务器可以返回多个结果集和更新计数,Hibernate将迭代结果,并将第一个结果集作为其返回值。其他所有结果都将被丢弃
- 如果您可以在您的过程中启用SETNOCOUNT ON,可能会更高效,但这不是一个要求
一种方法是使用getNamedQuery()
Query Query=session.getNamedQuery(“callStockStoreProcedure”)
.setParameter(“股票代码”、“7277”);
列表结果=query.List();
对于(int i=0;i,考虑以下仅返回基本返回值的存储过程:
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\u 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();
BigDecimal commentCount = (BigDecimal) entityManager
.createNativeQuery(
"SELECT fn_count_comments(:postId) FROM DUAL"
)
.setParameter("postId", 1L)
.getSingleResult();
您不能使用StoredProcedureRequesty
,因为它不适用于Hibernate 5,所以您可以这样称呼它:
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();
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 );
}
} );
有关更多详细信息,请参阅以下文章:
从hibernate调用存储过程的一种方法
在@namedNativeRequesties
注释中声明存储过程
//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());
}
//Stock.java
@命名请求({
@命名设备(
name=“callStockStoreProcedure”,
query=“调用GetStocks(:stockCode)”,
resultClass=Stock.class
)
})
@实体
@表(name=“股票”)
公共类Stock实现java.io.Serializable{
//使用getNamedQuery()调用它。
Query Query=session.getNamedQuery(“callStockStoreProcedure”)
.setParameter(“股票代码”、“7277”);
列表结果=query.List();
for(int i=0;iYou正在从hibernate会话检索连接,然后使用普通JDBC。此代码没有利用hibernate支持。此方法是否与RDBMs(Oracle和Sql Server)兼容请注意,JPA 2.1有EntityManager.CreateStoredProcedureRequesty
方法,如果JPA 2.0在类路径中,它将不会解析
//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());
}