从Java / JPA调用存储过程


Answers

我正在使用Jboss AS部署我的Web应用程序。 我应该使用JPA访问存储过程还是CallableStatement。 在这种情况下使用JPA的任何优势。

它不是真的被JPA支持,但它是doable 。 我仍然不会这样做:

  • 使用JPA只是为了在一些bean中映射一个存储过程调用的结果实在是太过于夸张,
  • 特别是鉴于JPA并不适合调用存储过程(语法将非常冗长)。

因此,我宁愿考虑使用Spring对JDBC数据访问的支持 ,或者像MyBatis这样的数据映射器,或者考虑到应用程序的简单性,使用原始JDBC和CallableStatement 。 实际上,JDBC可能是我的选择。 这是一个基本的开球例子:

CallableStatement cstmt = con.prepareCall("{call getEmployeeDetails(?, ?)}");
cstmt.setInt("employeeId", 123);
cstmt.setInt("companyId", 456);
ResultSet rs = cstmt.executeQuery();

参考

Question

我正在编写一个简单的Web应用程序来调用存储过程并检索一些数据。 它是一个非常简单的应用程序,它与客户端的数据库交互。 我们传递员工ID和公司ID,存储过程将返回员工详细信息。

Web应用程序无法更新/删除数据并正在使用SQL Server。

我正在使用Jboss AS部署我的Web应用程序。 我应该使用JPA访问存储过程还是CallableStatement 。 在这种情况下使用JPA的任何优势。

还有什么是sql语句来调用这个存储过程。 我以前从来没有使用过存储过程,而且我正在为此付出努力。 谷歌没有太多的帮助。

这里是存储过程:

CREATE procedure getEmployeeDetails (@employeeId int, @companyId int)
as
begin
    select firstName, 
           lastName, 
           gender, 
           address
      from employee et
     where et.employeeId = @employeeId
       and et.companyId = @companyId
end

更新:

对于使用JPA调用存储过程的其他人有问题。

Query query = em.createNativeQuery("{call getEmployeeDetails(?,?)}",
                                   EmployeeDetails.class)           
                                   .setParameter(1, employeeId)
                                   .setParameter(2, companyId);

List<EmployeeDetails> result = query.getResultList();

我已经注意到的事情:

  1. 参数名称对我无效,所以请尝试使用参数索引。
  2. 更正sql语句{call sp_name(?,?)}而不是call sp_name(?,?)
  3. 如果存储过程返回一个结果集,即使只知道一行, getSingleResult不会起作用
  4. 传递resultSetMapping名称或结果类的详细信息



要调用存储过程,我们可以在java.sql包中使用Callable Statement。




您需要将参数传递给存储过程。

它应该像这样工作:

    List result = em
      .createNativeQuery("call getEmployeeDetails(:employeeId,:companyId)")
      .setParameter("emplyoyeeId", 123L)
      .setParameter("companyId", 456L)
      .getResultList();

更新:

或者,也许它不应该。

在书籍EJB3 in Action中 ,它在第383页上说, JPA不支持存储过程 (页面只是预览,不能获得全文,整本书籍可在多个地方下载,包括这一个 ,我不知道这是否合法)。

无论如何,文字是这样的:

JPA和数据库存储过程

如果你是SQL的忠实粉丝,你可能愿意利用数据库存储过程的力量。 不幸的是,JPA不支持存储过程,并且您必须依赖持久性提供程序的专有功能。 但是,您可以使用简单的存储函数(不带出参数)和本机SQL查询。




您可以在存储库中使用@Query(value = "{call PROC_TEST()}", nativeQuery = true) 。 这对我有效。

注意:使用'{'和'}',否则它将无法工作。




对Sql Srver来说可能不一样,但对于使用oracle和eclipslink的人来说,它对我来说很有用

例如:有一个IN参数(CHAR类型)和两个OUT参数(NUMBER&VARCHAR)的过程

在persistence.xml中声明持久性单元:

<persistence-unit name="presistanceNameOfProc" transaction-type="RESOURCE_LOCAL">
    <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
    <jta-data-source>jdbc/DataSourceName</jta-data-source>
    <mapping-file>META-INF/eclipselink-orm.xml</mapping-file>
    <properties>
        <property name="eclipselink.logging.level" value="FINEST"/>
        <property name="eclipselink.logging.logger" value="DefaultLogger"/>
        <property name="eclipselink.weaving" value="static"/>
        <property name="eclipselink.ddl.table-creation-suffix" value="JPA_STORED_PROC" />
    </properties>
</persistence-unit>

并在eclipselink-orm.xml中声明proc的结构

<?xml version="1.0" encoding="UTF-8"?><entity-mappings version="2.0"
xmlns="http://java.sun.com/xml/ns/persistence/orm" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence/orm orm_2_0.xsd">
<named-stored-procedure-query name="PERSIST_PROC_NAME" procedure-name="name_of_proc" returns-result-set="false">
    <parameter direction="IN" name="in_param_char" query-parameter="in_param_char" type="Character"/>
    <parameter direction="OUT" name="out_param_int" query-parameter="out_param_int" type="Integer"/>
    <parameter direction="OUT" name="out_param_varchar" query-parameter="out_param_varchar" type="String"/>
</named-stored-procedure-query>

在代码中你只需要像这样调用你的proc:

try {
        final Query query = this.entityManager
                .createNamedQuery("PERSIST_PROC_NAME");
        query.setParameter("in_param_char", 'V'); 
        resultQuery = (Object[]) query.getSingleResult();

    } catch (final Exception ex) {
        LOGGER.log(ex);
        throw new TechnicalException(ex);
    }

得到两个输出参数:

Integer myInt = (Integer) resultQuery[0];
String myStr =  (String) resultQuery[1];



如果你有实体经理,这个答案可能会有帮助

我有一个存储过程来创建下一个数字,并在服务器端我有缝框架。

客户端

 Object on = entityManager.createNativeQuery("EXEC getNextNmber").executeUpdate();
        log.info("New order id: " + on.toString());

数据库端(SQL服务器)我有一个名为getNextNmber存储过程




  1. 对于使用这种IN / OUT参数的简单存储过程

    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);
    
  2. 对于使用SYS_REFCURSOR OUT参数的存储过程:

    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();
    
  3. 对于如下所示的SQL函数:

    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;
    

    你可以这样称呼它:

    BigDecimal commentCount = (BigDecimal) entityManager
    .createNativeQuery(
        "SELECT fn_count_comments(:postId) FROM DUAL"
    )
    .setParameter("postId", 1L)
    .getSingleResult();
    

    至少在使用Hibernate 4.x和5.x时,因为JPA StoredProcedureQuery不适用于SQL FUNCTIONS。

有关如何在使用JPA和Hibernate时调用存储过程和函数的更多详细信息,请查看以下文章









Related