简体   繁体   English

如何从 Java 和 JPA 调用存储过程

[英]How to call a stored procedure from Java and JPA

I am writing a simple web application to call a stored procedure and retrieve some data.我正在编写一个简单的 web 应用程序来调用存储过程并检索一些数据。 Its a very simple application, which interacts with client's database.它是一个非常简单的应用程序,它与客户的数据库进行交互。 We pass employee id and company id and the stored procedure will return employee details.我们传递员工 ID 和公司 ID,存储过程将返回员工详细信息。

Web application cannot update/delete data and is using SQL Server. Web 应用程序无法更新/删除数据,并且正在使用 SQL 服务器。

I am deploying my web application in Jboss AS.我正在 Jboss AS 中部署我的 web 应用程序。 Should I use JPA to access the stored procedure or CallableStatement .我应该使用 JPA 来访问存储过程还是CallableStatement Any advantage of using JPA in this case.在这种情况下使用 JPA 的任何优势。

Also what will be the sql statement to call this stored procedure.还有什么是 sql 语句来调用这个存储过程。 I have never used stored procedures before and I am struggling with this one.我以前从未使用过存储过程,我正在努力解决这个问题。 Google was not much of a help.谷歌没有太大帮助。

Here is the stored procedure:这是存储过程:

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

Update:更新:

For anyone else having problem calling stored procedure using JPA .对于使用JPA调用存储过程时遇到问题的任何其他人。

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

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

Things I have noticed:我注意到的事情:

  1. Parameter names didn't work for me, so try using parameter index.参数名称对我不起作用,因此请尝试使用参数索引。
  2. Correct sql statement {call sp_name(?,?)} instead of call sp_name(?,?)更正 sql 语句{call sp_name(?,?)}而不是call sp_name(?,?)
  3. If stored procedure is returning a result set, even if you know with only one row, getSingleResult wont work如果存储过程返回结果集,即使您只知道一行, getSingleResult不会工作
  4. Pass a resultSetMapping name or result class details传递一个resultSetMapping名称或结果 class 详细信息

JPA 2.1 now support Stored Procedure, read the Java doc here . JPA 2.1 现在支持存储过程,请在此处阅读 Java 文档。

Example:例子:

StoredProcedureQuery storedProcedure = em.createStoredProcedureQuery("sales_tax");
// set parameters
storedProcedure.registerStoredProcedureParameter("subtotal", Double.class, ParameterMode.IN);
storedProcedure.registerStoredProcedureParameter("tax", Double.class, ParameterMode.OUT);
storedProcedure.setParameter("subtotal", 1f);
// execute SP
storedProcedure.execute();
// get result
Double tax = (Double)storedProcedure.getOutputParameterValue("tax");

See detailed examplehere .请参阅此处的详细示例。

I am deploying my web application in Jboss AS.我正在 Jboss AS 中部署我的 Web 应用程序。 Should I use JPA to access the stored procedure or CallableStatement.我应该使用 JPA 来访问存储过程还是 CallableStatement。 Any advantage of using JPA in this case.在这种情况下使用 JPA 的任何优势。

It is not really supported by JPA but it's doable . JPA 并不真正支持它,但它是可行的 Still I wouldn't go this way:我仍然不会走这条路:

  • using JPA just to map the result of a stored procedure call in some beans is really overkill,仅使用 JPA 来映射某些 bean 中存储过程调用的结果确实有点矫枉过正,
  • especially given that JPA is not really appropriate to call stored procedure (the syntax will be pretty verbose).特别是考虑到 JPA 不太适合调用存储过程(语法将非常冗长)。

I would thus rather consider using Spring support for JDBC data access , or a data mapper like MyBatis or, given the simplicity of your application, raw JDBC and CallableStatement .因此,我宁愿考虑使用Spring 对 JDBC 数据访问的支持,或者像MyBatis这样的数据映射器,或者考虑到您的应用程序的简单性,原始 JDBC 和CallableStatement Actually, JDBC would probably be my choice.实际上,JDBC 可能是我的选择。 Here is a basic kickoff example:这是一个基本的开球示例:

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

Reference参考

You need to pass the parameters to the stored procedure.您需要将参数传递给存储过程。

It should work like this:它应该像这样工作:

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

Update:更新:

Or maybe it shouldn't.或者也许它不应该。

In the Book EJB3 in Action , it says on page 383, that JPA does not support stored procedures (page is only a preview, you don't get the full text, the entire book is available as a download in several places including this one , I don't know if this is legal though).在 Book EJB3 in Action 中,它在第 383 页说, JPA 不支持存储过程(页面只是预览,你没有得到全文,整本书可以在几个地方下载,包括这个,我不知道这是否合法)。

Anyway, the text is this:不管怎样,正文是这样的:

JPA and database stored procedures JPA 和数据库存储过程

If you're a big fan of SQL, you may be willing to exploit the power of database stored procedures.如果您是 SQL 的忠实粉丝,您可能愿意利用数据库存储过程的强大功能。 Unfortunately, JPA doesn't support stored procedures, and you have to depend on a proprietary feature of your persistence provider.不幸的是,JPA 不支持存储过程,您必须依赖持久性提供程序的专有功能。 However, you can use simple stored functions (without out parameters) with a native SQL query.但是,您可以在本机 SQL 查询中使用简单的存储函数(不带输出参数)。

  1. For a simple stored procedure that using IN/OUT parameters like this对于使用这样的 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;

    You can call it from JPA as follows:您可以从 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. For a stored procedure which uses a SYS_REFCURSOR OUT parameter:对于使用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;

    You can call it as follows:您可以按如下方式调用它:

     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. For a SQL function that looks as follows:对于如下所示的 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;

    You can call it like this:你可以这样称呼它:

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

    At least when using Hibernate 4.x and 5.x because the JPA StoredProcedureQuery does not work for SQL FUNCTIONS.至少在使用 Hibernate 4.x 和 5.x 时,因为 JPA StoredProcedureQuery不适用于 SQL FUNCTIONS。

For more details about how to call stored procedures and functions when using JPA and Hibernate, check out the following articles有关在使用 JPA 和 Hibernate 时如何调用存储过程和函数的更多详细信息,请查看以下文章

How to retrieve Stored Procedure output parameter using JPA (2.0 needs EclipseLink imports and 2.1 does not)如何使用 JPA 检索存储过程输出参数(2.0 需要 EclipseLink 导入,而 2.1 不需要)

Even though this answer does elaborate on returning a recordset from a stored procedure, I am posting here, because it took me ages to figure it out and this thread helped me.尽管这个答案确实详细说明了从存储过程返回记录集,但我还是在这里发帖,因为我花了很长时间才弄明白,这个线程帮助了我。

My application was using Eclipselink-2.3.1, but I will force an upgrade to Eclipselink-2.5.0, as JPA 2.1 has much better support for stored procedures.我的应用程序使用 Eclipselink-2.3.1,但我将强制升级到 Eclipselink-2.5.0,因为 JPA 2.1 对存储过程有更好的支持。

Using EclipseLink-2.3.1/JPA-2.0: Implementation-Dependent使用 EclipseLink-2.3.1/JPA-2.0:依赖于实现

This method requires imports of EclipseLink classes from "org.eclipse.persistence", so it is specific to Eclipselink implementation.此方法需要从“org.eclipse.persistence”导入 EclipseLink 类,因此它特定于 Eclipselink 实现。

I found it at " http://www.yenlo.nl/en/calling-oracle-stored-procedures-from-eclipselink-with-multiple-out-parameters ".我在“ http://www.yenlo.nl/en/calling-oracle-stored-procedures-from-eclipselink-with-multiple-out-parameters ”找到它。

StoredProcedureCall storedProcedureCall = new StoredProcedureCall();
storedProcedureCall.setProcedureName("mypackage.myprocedure");
storedProcedureCall.addNamedArgument("i_input_1"); // Add input argument name.
storedProcedureCall.addNamedOutputArgument("o_output_1"); // Add output parameter name.
DataReadQuery query = new DataReadQuery();
query.setCall(storedProcedureCall);
query.addArgument("i_input_1"); // Add input argument names (again);
List<Object> argumentValues = new ArrayList<Object>();
argumentValues.add("valueOf_i_input_1"); // Add input argument values.
JpaEntityManager jpaEntityManager = (JpaEntityManager) getEntityManager();
Session session = jpaEntityManager.getActiveSession();
List<?> results = (List<?>) session.executeQuery(query, argumentValues);
DatabaseRecord record = (DatabaseRecord) results.get(0);
String result = String.valueOf(record.get("o_output_1")); // Get output parameter

Using EclipseLink-2.5.0/JPA-2.1: Implementation-Independent (documented already in this thread)使用 EclipseLink-2.5.0/JPA-2.1:与实现无关(已在此线程中记录)

This method is implementation independent (don't need Eclipslink imports).此方法与实现无关(不需要 Eclipslink 导入)。

StoredProcedureQuery query = getEntityManager().createStoredProcedureQuery("mypackage.myprocedure");
query.registerStoredProcedureParameter("i_input_1", String.class, ParameterMode.IN);
query.registerStoredProcedureParameter("o_output_1", String.class, ParameterMode.OUT);
query.setParameter("i_input_1", "valueOf_i_input_1");
boolean queryResult = query.execute();
String result = String.valueOf(query.getOutputParameterValue("o_output_1"));

For me, only the following worked with Oracle 11g and Glassfish 2.1 (Toplink):对我来说,只有以下内容适用于 Oracle 11g 和 Glassfish 2.1 (Toplink):

Query query = entityManager.createNativeQuery("BEGIN PROCEDURE_NAME(); END;");
query.executeUpdate();

The variant with curly braces resulted in ORA-00900.带有花括号的变体导致 ORA-00900。

If using EclipseLink you can use the @NamedStoredProcedureQuery or StoreProcedureCall to execute any stored procedure, including ones with output parameters, or out cursors.如果使用 EclipseLink,您可以使用 @NamedStoredProcedureQuery 或 StoreProcedureCall 来执行任何存储过程,包括带有输出参数或输出游标的存储过程。 Support for stored functions and PLSQL data-types is also available.还提供对存储函数和 PLSQL 数据类型的支持。

See, http://en.wikibooks.org/wiki/Java_Persistence/Advanced_Topics#Stored_Procedures见, http://en.wikibooks.org/wiki/Java_Persistence/Advanced_Topics#Stored_Procedures

The following works for me:以下对我有用:

Query query = em.createNativeQuery("BEGIN VALIDACIONES_QPAI.RECALC_COMP_ASSEMBLY('X','X','X',0); END;");
query.executeUpdate();

May be it's not the same for Sql Srver but for people using oracle and eclipslink it's working for me对于 Sql Srver 可能不一样,但对于使用 oracle 和 eclipslink 的人来说,它对我有用

ex: a procedure that have one IN param (type CHAR) and two OUT params (NUMBER & VARCHAR)例如:具有一个 IN 参数(类型 CHAR)和两个 OUT 参数(NUMBER & VARCHAR)的过程

in the persistence.xml declare the persistence-unit :在persistence.xml 中声明persistence-unit:

<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>

and declare the structure of the proc in the eclipselink-orm.xml并在 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>

in the code you just have to call your proc like this :在代码中,您只需像这样调用 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);
    }

to get the two output params :获取两个输出参数:

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

This worked for me.这对我有用。

@Entity
@Table(name="acct")
@NamedNativeQueries({
 @NamedNativeQuery(callable=true, name="Account.findOne", query="call sp_get_acct(?), resultClass=Account.class)})
public class Account{
 // Code 
}

Note : in future if you decide to use default version of findOne then just comment the NamedNativeQueries annotation and JPA will switch to default注意:将来如果您决定使用 findOne 的默认版本,那么只需注释 NamedNativeQueries 注释,JPA 将切换到默认版本

This answer might be helpful if you have entity manager如果您有实体管理器,此答案可能会有所帮助

I had a stored procedure to create next number and on server side I have seam framework.我有一个存储过程来创建下一个数字,在服务器端我有接缝框架。

Client side客户端

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

Database Side (SQL server) I have stored procedure named getNextNmber数据库端(SQL 服务器)我有一个名为getNextNmber存储过程

You can use @Query(value = "{call PROC_TEST()}", nativeQuery = true) in your repository.您可以在存储库中使用@Query(value = "{call PROC_TEST()}", nativeQuery = true) This worked for me.这对我有用。

Attention: use '{' and '}' or else it will not work.注意:使用 '{' 和 '}' 否则将不起作用。

JPA 2.0 doesn't support RETURN values, only calls. JPA 2.0 不支持 RETURN 值,只支持调用。

My solution was.我的解决方案是。 Create a FUNCTION calling PROCEDURE.创建一个调用 PROCEDURE 的函数。

So, inside JAVA code you execute a NATIVE QUERY calling the oracle FUNCTION.因此,在 JAVA 代码中,您执行一个调用 oracle FUNCTION 的 NATIVE QUERY。

Try this code:试试这个代码:

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

persistence.xml持久化文件

 <persistence-unit name="PU2" transaction-type="RESOURCE_LOCAL">
<non-jta-data-source>jndi_ws2</non-jta-data-source>
<exclude-unlisted-classes>false</exclude-unlisted-classes>
<properties/>

codigo java爪哇爪哇

  String PERSISTENCE_UNIT_NAME = "PU2";
    EntityManagerFactory factory2;
    factory2 = Persistence.createEntityManagerFactory(PERSISTENCE_UNIT_NAME);

    EntityManager em2 = factory2.createEntityManager();
    boolean committed = false;
    try {

        try {
            StoredProcedureQuery storedProcedure = em2.createStoredProcedureQuery("PKCREATURNO.INSERTATURNO");
            // set parameters
            storedProcedure.registerStoredProcedureParameter("inuPKEMPRESA", BigDecimal.class, ParameterMode.IN);
            storedProcedure.registerStoredProcedureParameter("inuPKSERVICIO", BigDecimal.class, ParameterMode.IN);
            storedProcedure.registerStoredProcedureParameter("inuPKAREA", BigDecimal.class, ParameterMode.IN);
            storedProcedure.registerStoredProcedureParameter("isbCHSIGLA", String.class, ParameterMode.IN);
            storedProcedure.registerStoredProcedureParameter("INUSINCALIFICACION", BigInteger.class, ParameterMode.IN);
            storedProcedure.registerStoredProcedureParameter("INUTIMBRAR", BigInteger.class, ParameterMode.IN);
            storedProcedure.registerStoredProcedureParameter("INUTRANSFERIDO", BigInteger.class, ParameterMode.IN);
            storedProcedure.registerStoredProcedureParameter("INTESTADO", BigInteger.class, ParameterMode.IN);
            storedProcedure.registerStoredProcedureParameter("inuContador", BigInteger.class, ParameterMode.OUT);

            BigDecimal inuPKEMPRESA = BigDecimal.valueOf(1);
            BigDecimal inuPKSERVICIO = BigDecimal.valueOf(5);
            BigDecimal inuPKAREA = BigDecimal.valueOf(23);
            String isbCHSIGLA = "";
            BigInteger INUSINCALIFICACION = BigInteger.ZERO;
            BigInteger INUTIMBRAR = BigInteger.ZERO;
            BigInteger INUTRANSFERIDO = BigInteger.ZERO;
            BigInteger INTESTADO = BigInteger.ZERO;
            BigInteger inuContador = BigInteger.ZERO;

            storedProcedure.setParameter("inuPKEMPRESA", inuPKEMPRESA);
            storedProcedure.setParameter("inuPKSERVICIO", inuPKSERVICIO);
            storedProcedure.setParameter("inuPKAREA", inuPKAREA);
            storedProcedure.setParameter("isbCHSIGLA", isbCHSIGLA);
            storedProcedure.setParameter("INUSINCALIFICACION", INUSINCALIFICACION);
            storedProcedure.setParameter("INUTIMBRAR", INUTIMBRAR);
            storedProcedure.setParameter("INUTRANSFERIDO", INUTRANSFERIDO);
            storedProcedure.setParameter("INTESTADO", INTESTADO);
            storedProcedure.setParameter("inuContador", inuContador);

            // execute SP
            storedProcedure.execute();
            // get result

            try {
                long _inuContador = (long) storedProcedure.getOutputParameterValue("inuContador");
                varCon = _inuContador + "";
            } catch (Exception e) {
            } 
        } finally {

        }
    } finally {
        em2.close();
    }

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

从 JPA 2.1 开始,JPA 支持使用动态 StoredProcedureQuery 和声明式 @NamedStoredProcedureQuery 调用存储过程。

the simplest way is to use JpaRepository最简单的方法是使用 JpaRepository

1- Create a stored procedure
CREATE PROCEDURE dbo.getEmployeeDetails
(
@employeeId         int,
@companyId          int
)  AS
BEGIN
 SELECT firstName,lastName,gender,address
 FROM employee et
 WHERE et.employeeId = @employeeId and et.companyId = @companyId
END


2- Create Entity
@Getter
@Setter
@ToString
@NoArgsConstructor
@AllArgsConstructor
@Entity
public class EmployeeDetails {
    @Id
    private String firstName;
    private String lastName;
    private String gender;
    private String address;
 }


3- Create Repository
public interface EmployeeDetailsRepository extends 
JpaRepository<EmployeeDetails,String> {
@Query(value = "EXEC dbo.getEmployeeDetails @employeeId=:empId, 
                                          @companyId=:compId",nativeQuery =true)
List<EmployeeDetails> getEmployeeList(@Param("employeeId") Integer empId, 
                                      @Param("companyId") Integer compId);
}

4- create Controller
@CrossOrigin(origins = "*")
@RestController
@RequestMapping(value = "/api/employee")
public class EmployeeController {

@Autowired
private EmployeeDetailsRepository empRepo;

@GetMapping(value = "/details")
public ResponseEntity<List<EmployeeDetails>> getEmployeeDetails(@RequestParam 
            String empId, @RequestParam String compId) {
try {
   List<EmployeeDetails> result = empRepo.getEmployeeList(
                                Integer.valueOf(empId),Integer.valueOf(compId));
        return ResponseEntity.status(HttpStatus.OK).body(result);
    }
    catch (Exception ex)
    {
        return ResponseEntity.status(HttpStatus.EXPECTATION_FAILED).body(null);
    }
}
}

If you're not too attached to calling this particular procedure with JPA or JDBC, you could use jOOQ, a third party library that generates stubs for all of your stored procedures to simplify calling them, and making the calls type safe.如果您不太喜欢使用 JPA 或 JDBC 调用此特定过程,则可以使用jOOQ,这是一个第三方库,可为您的所有存储过程生成存根以简化调用它们,并使调用类型安全。

Calling procedures returning unspecified cursors调用返回未指定游标的过程

In your particular case, the procedure returns an untyped, undeclared cursor (it could return several cursors and interleaved update counts).在您的特定情况下,该过程返回一个无类型、未声明的 cursor (它可能返回多个游标和交错更新计数)。 So, you could call the procedure like this with jOOQ:因此,您可以使用 jOOQ 调用这样的过程:

GetEmployeeDetails proc = new GetEmployeeDetails();
proc.setEmployeeId(1);
proc.setCompanyId(2);
proc.execute(configuration);

// Iterate over potentially multiple results
for (Result<?> result : proc.getResults()) {

    // Print the first result set (your employee query)
    System.out.println(result);

    // Use your implicit knowledge of the content of the query
    // Without type safety
    for (Record record : result) {

        // All tables / columns are also generated
        System.out.println("First name: " + record.get(EMPLOYEE.FIRSTNAME));
        System.out.println("Last name: " + record.get(EMPLOYEE.LASTNAME));
        System.out.println("Gender: " + record.get(EMPLOYEE.GENDER));
        System.out.println("Address: " + record.get(EMPLOYEE.ADDRESS));
    }
}

Using an actual table valued function, instead使用实际表值 function,而不是

Personally, I don't really like that feature of a few RDBMS (including SQL Server, MySQL) of returning arbitrary untyped cursors.就个人而言,我不太喜欢一些 RDBMS(包括 SQL Server、MySQL)返回任意无类型游标的特性。 Why not just declare the result type?为什么不直接声明结果类型? SQL Server has powerful table valued functions . SQL 服务器具有强大的表值功能 Eg just use this syntax here:例如,只需在此处使用此语法:

CREATE FUNCTION getEmployeeDetails (@employeeId int, @companyId int)
RETURNS TABLE
AS RETURN
  SELECT
    firstName,
    lastName,
    gender,
    address
  FROM employee et
  WHERE et.employeeId = @employeeId
  AND et.companyId = @companyId

Now, you have the full type information associated with this function in your catalog, and if you're still using jOOQ, that information will be available to the code generator, so you can call the function like this:现在,您的目录中有与此 function 相关联的完整类型信息,如果您仍在使用 jOOQ,代码生成器将可以使用该信息,因此您可以像这样调用 function:

for (GetEmployeeDetailsRecord record : ctx.selectFrom(getEmployeeDetails(1, 2))) {
    System.out.println("First name: " + record.getFirstName());
    System.out.println("Last name: " + record.getLastName());
    System.out.println("Gender: " + record.getGender());
    System.out.println("Address: " + record.getAddress());
}

Disclaimer: I work for the company behind jOOQ免责声明:我为 jOOQ 背后的公司工作

I am writing a simple web application to call a stored procedure and retrieve some data.我正在编写一个简单的Web应用程序以调用存储过程并检索一些数据。 Its a very simple application, which interacts with client's database.它是一个非常简单的应用程序,可以与客户的数据库进行交互。 We pass employee id and company id and the stored procedure will return employee details.我们传递员工ID和公司ID,并且存储过程将返回员工详细信息。

Web application cannot update/delete data and is using SQL Server. Web应用程序无法更新/删除数据,并且正在使用SQL Server。

I am deploying my web application in Jboss AS.我正在将Web应用程序部署在Jboss AS中。 Should I use JPA to access the stored procedure or CallableStatement .我应该使用JPA访问存储过程还是CallableStatement Any advantage of using JPA in this case.在这种情况下使用JPA的任何优势。

Also what will be the sql statement to call this stored procedure.调用该存储过程的sql语句也将是什么。 I have never used stored procedures before and I am struggling with this one.我以前从未使用过存储过程,因此我正在为此而苦苦挣扎。 Google was not much of a help. Google并没有太大帮助。

Here is the stored procedure:这是存储过程:

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

Update:更新:

For anyone else having problem calling stored procedure using JPA .对于使用JPA调用存储过程时遇到问题的其他任何人。

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

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

Things I have noticed:我注意到的事情:

  1. Parameter names didn't work for me, so try using parameter index.参数名称对我不起作用,因此请尝试使用参数索引。
  2. Correct sql statement {call sp_name(?,?)} instead of call sp_name(?,?)正确的sql语句{call sp_name(?,?)}而不是call sp_name(?,?)
  3. If stored procedure is returning a result set, even if you know with only one row, getSingleResult wont work如果存储过程正在返回结果集,即使您只知道一行, getSingleResult无法工作
  4. Pass a resultSetMapping name or result class details传递resultSetMapping名称或结果类详细信息

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM