Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/database/8.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 如何使用Hibernate和JPA调用存储过程?_Java_Database_Hibernate_Stored Procedures_Orm - Fatal编程技术网

Java 如何使用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

如何使用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();

请根据需要添加异常处理

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

映射

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